From f03acc635f442fa6a2c844c9bc48dfc4a46dcf43 Mon Sep 17 00:00:00 2001 From: transcoder Date: Wed, 12 Feb 2014 04:09:36 -0700 Subject: [PATCH] Version 1.1.0.0 update --- .cproject | 140 + .gitignore | 31 +- .project | 27 + COPYING | 5 +- INSTALL | 2 +- casinocoin-qt.pro | 199 +- contrib/bitrpc/bitrpc.py | 10 +- contrib/debian/README | 20 + contrib/debian/bin/.svn/entries | 62 + .../bin/.svn/text-base/bitcoind.svn-base | 14 + contrib/debian/bitcoin-qt.desktop | 4 +- contrib/debian/bitcoin-qt.install | 3 +- contrib/debian/bitcoind.install | 3 +- contrib/debian/changelog | 42 + contrib/debian/control | 4 - contrib/debian/copyright | 5 +- contrib/debian/examples/bitcoin.conf | 10 +- contrib/debian/manpages/bitcoin-qt.1 | 206 + contrib/debian/manpages/bitcoin.conf.5 | 18 +- contrib/debian/manpages/bitcoind.1 | 8 +- contrib/gitian-descriptors/README | 65 +- contrib/gitian-descriptors/boost-win32.yml | 72 +- contrib/gitian-descriptors/deps-win32.yml | 91 +- contrib/gitian-descriptors/gitian-win32.yml | 56 +- contrib/gitian-descriptors/gitian.yml | 8 +- contrib/gitian-descriptors/qt-win32.yml | 50 +- contrib/gitian-downloader/aspect-key.pgp | 20 + contrib/gitian-downloader/coblee-key.pgp | 75 + contrib/gitian-downloader/face-key.pgp | 54 + .../gitian-downloader/linux-download-config | 20 + contrib/gitian-downloader/thrasher-key.pgp | 30 + .../gitian-downloader/win32-download-config | 20 + contrib/gitian-downloader/wtogami-key.pgp | 131 + contrib/macdeploy/background.png | Bin 16827 -> 13651 bytes contrib/macdeploy/macdeployqtplus | 113 +- contrib/macdeploy/notes.txt | 2 +- contrib/pyminer/example-config.cfg | 2 +- contrib/pyminer/pyminer.py | 4 +- contrib/seeds/README | 9 + contrib/seeds/makeseeds.py | 32 + contrib/spendfrom/README | 32 + contrib/spendfrom/setup.py | 9 + contrib/spendfrom/spendfrom.py | 267 ++ contrib/test-patches/README | 4 + contrib/testgen/README | 1 + contrib/testgen/base58.py | 104 + contrib/testgen/gen_base58_test_vectors.py | 126 + contrib/tidy_datadir.sh | 59 + contrib/wallettools/.svn/entries | 96 + .../text-base/walletchangepass.py.svn-base | 5 + .../.svn/text-base/walletunlock.py.svn-base | 4 + contrib/wallettools/walletchangepass.py | 4 +- contrib/wallettools/walletunlock.py | 4 +- doc/Doxyfile | 4 +- doc/README.md | 47 + doc/README_windows.txt | 23 +- doc/Tor.txt | 38 +- doc/assets-attribution.txt | 30 +- doc/bitcoin_logo_doxygen.png | Bin 5735 -> 4757 bytes doc/build-msw.md | 89 + doc/build-osx.md | 185 + doc/build-unix.md | 154 + doc/coding.md | 94 + doc/files.txt | 19 + doc/multiwallet-qt.md | 52 + doc/readme-qt.rst | 69 +- doc/release-notes.md | 100 + doc/release-process.md | 161 + doc/translation_process.md | 6 +- doc/unit-tests.md | 35 + share/certs/BitcoinFoundation_Apple_Cert.pem | 37 + share/certs/BitcoinFoundation_Comodo_Cert.pem | 37 + share/certs/PrivateKeyNotes.md | 46 + share/pixmaps/bitcoin-bc.ico | Bin 15086 -> 15086 bytes share/pixmaps/bitcoin.ico | Bin 42583 -> 89957 bytes share/pixmaps/bitcoin128.png | Bin 0 -> 16587 bytes share/pixmaps/bitcoin128.xpm | 1084 +++++ share/pixmaps/bitcoin16.png | Bin 0 -> 871 bytes share/pixmaps/bitcoin16.xpm | 167 + share/pixmaps/bitcoin256.png | Bin 0 -> 50148 bytes share/pixmaps/bitcoin256.xpm | 1969 +++++++++ share/pixmaps/bitcoin32.png | Bin 0 -> 2203 bytes share/pixmaps/bitcoin32.xpm | 458 +- share/pixmaps/bitcoin64.png | Bin 0 -> 5922 bytes share/pixmaps/bitcoin64.xpm | 612 +++ share/pixmaps/favicon.ico | Bin 6702 -> 5430 bytes share/pixmaps/nsis-header.bmp | Bin 25818 -> 25820 bytes share/pixmaps/nsis-wizard.bmp | Bin 154542 -> 154544 bytes share/qt/Info.plist | 37 + share/qt/clean_mac_info_plist.py | 29 + share/setup.nsi | 14 +- src/addrman.cpp | 7 +- src/addrman.h | 12 +- src/alert.cpp | 258 ++ src/alert.h | 102 + src/allocators.h | 185 +- src/base58.h | 44 +- src/bignum.h | 80 +- src/bitcoinrpc.cpp | 2684 ++---------- src/bitcoinrpc.h | 144 +- src/bloom.cpp | 182 + src/bloom.h | 91 + src/checkpoints.cpp | 130 +- src/checkpoints.h | 6 +- src/checkqueue.h | 192 + src/clientversion.h | 26 + src/coincontrol.h | 57 + src/compat.h | 3 +- src/crypter.cpp | 24 +- src/crypter.h | 21 +- src/db.cpp | 612 +-- src/db.h | 67 +- src/hash.cpp | 58 + src/hash.h | 126 + src/init.cpp | 923 ++-- src/init.h | 7 +- src/json/json_spirit_writer_template.h | 3 +- src/key.cpp | 503 +-- src/key.h | 260 +- src/keystore.cpp | 88 +- src/keystore.h | 23 +- src/leveldb.cpp | 81 + src/leveldb.h | 153 + src/leveldb/.gitignore | 13 + src/leveldb/AUTHORS | 11 + src/leveldb/LICENSE | 27 + src/leveldb/NEWS | 17 + src/leveldb/README | 51 + src/leveldb/TODO | 14 + src/leveldb/WINDOWS.md | 39 + src/leveldb/build_detect_platform | 214 + src/leveldb/db/autocompact_test.cc | 118 + src/leveldb/db/builder.cc | 88 + src/leveldb/db/builder.h | 34 + src/leveldb/db/c.cc | 595 +++ src/leveldb/db/c_test.c | 390 ++ src/leveldb/db/corruption_test.cc | 352 ++ src/leveldb/db/db_bench.cc | 979 +++++ src/leveldb/db/db_impl.cc | 1498 +++++++ src/leveldb/db/db_impl.h | 210 + src/leveldb/db/db_iter.cc | 316 ++ src/leveldb/db/db_iter.h | 28 + src/leveldb/db/db_test.cc | 2092 +++++++++ src/leveldb/db/dbformat.cc | 140 + src/leveldb/db/dbformat.h | 230 + src/leveldb/db/dbformat_test.cc | 112 + src/leveldb/db/filename.cc | 139 + src/leveldb/db/filename.h | 80 + src/leveldb/db/filename_test.cc | 122 + src/leveldb/db/leveldb_main.cc | 238 + src/leveldb/db/log_format.h | 35 + src/leveldb/db/log_reader.cc | 259 ++ src/leveldb/db/log_reader.h | 108 + src/leveldb/db/log_test.cc | 500 +++ src/leveldb/db/log_writer.cc | 103 + src/leveldb/db/log_writer.h | 48 + src/leveldb/db/memtable.cc | 145 + src/leveldb/db/memtable.h | 91 + src/leveldb/db/repair.cc | 389 ++ src/leveldb/db/skiplist.h | 379 ++ src/leveldb/db/skiplist_test.cc | 378 ++ src/leveldb/db/snapshot.h | 66 + src/leveldb/db/table_cache.cc | 121 + src/leveldb/db/table_cache.h | 61 + src/leveldb/db/version_edit.cc | 266 ++ src/leveldb/db/version_edit.h | 107 + src/leveldb/db/version_edit_test.cc | 46 + src/leveldb/db/version_set.cc | 1531 +++++++ src/leveldb/db/version_set.h | 398 ++ src/leveldb/db/version_set_test.cc | 179 + src/leveldb/db/write_batch.cc | 147 + src/leveldb/db/write_batch_internal.h | 49 + src/leveldb/db/write_batch_test.cc | 120 + src/leveldb/doc/bench/db_bench_sqlite3.cc | 718 ++++ src/leveldb/doc/bench/db_bench_tree_db.cc | 528 +++ src/leveldb/doc/benchmark.html | 459 ++ src/leveldb/doc/doc.css | 89 + src/leveldb/doc/impl.html | 213 + src/leveldb/doc/index.html | 549 +++ src/leveldb/doc/log_format.txt | 75 + src/leveldb/doc/table_format.txt | 104 + src/leveldb/helpers/memenv/memenv.cc | 384 ++ src/leveldb/helpers/memenv/memenv.h | 20 + src/leveldb/helpers/memenv/memenv_test.cc | 232 + src/leveldb/include/leveldb/c.h | 291 ++ src/leveldb/include/leveldb/cache.h | 99 + src/leveldb/include/leveldb/comparator.h | 63 + src/leveldb/include/leveldb/db.h | 161 + src/leveldb/include/leveldb/env.h | 333 ++ src/leveldb/include/leveldb/filter_policy.h | 70 + src/leveldb/include/leveldb/iterator.h | 100 + src/leveldb/include/leveldb/options.h | 195 + src/leveldb/include/leveldb/slice.h | 109 + src/leveldb/include/leveldb/status.h | 106 + src/leveldb/include/leveldb/table.h | 85 + src/leveldb/include/leveldb/table_builder.h | 92 + src/leveldb/include/leveldb/write_batch.h | 64 + src/leveldb/issues/issue178_test.cc | 92 + src/leveldb/port/README | 10 + src/leveldb/port/atomic_pointer.h | 224 + src/leveldb/port/port.h | 21 + src/leveldb/port/port_example.h | 135 + src/leveldb/port/port_posix.cc | 54 + src/leveldb/port/port_posix.h | 161 + src/leveldb/port/port_win.cc | 147 + src/leveldb/port/port_win.h | 174 + src/leveldb/port/thread_annotations.h | 59 + src/leveldb/port/win/stdint.h | 24 + src/leveldb/table/block.cc | 268 ++ src/leveldb/table/block.h | 44 + src/leveldb/table/block_builder.cc | 109 + src/leveldb/table/block_builder.h | 57 + src/leveldb/table/filter_block.cc | 111 + src/leveldb/table/filter_block.h | 68 + src/leveldb/table/filter_block_test.cc | 128 + src/leveldb/table/format.cc | 145 + src/leveldb/table/format.h | 108 + src/leveldb/table/iterator.cc | 67 + src/leveldb/table/iterator_wrapper.h | 63 + src/leveldb/table/merger.cc | 197 + src/leveldb/table/merger.h | 26 + src/leveldb/table/table.cc | 275 ++ src/leveldb/table/table_builder.cc | 270 ++ src/leveldb/table/table_test.cc | 868 ++++ src/leveldb/table/two_level_iterator.cc | 182 + src/leveldb/table/two_level_iterator.h | 34 + src/leveldb/util/arena.cc | 68 + src/leveldb/util/arena.h | 68 + src/leveldb/util/arena_test.cc | 68 + src/leveldb/util/bloom.cc | 95 + src/leveldb/util/bloom_test.cc | 160 + src/leveldb/util/cache.cc | 325 ++ src/leveldb/util/cache_test.cc | 186 + src/leveldb/util/coding.cc | 194 + src/leveldb/util/coding.h | 104 + src/leveldb/util/coding_test.cc | 196 + src/leveldb/util/comparator.cc | 81 + src/leveldb/util/crc32c.cc | 332 ++ src/leveldb/util/crc32c.h | 45 + src/leveldb/util/crc32c_test.cc | 72 + src/leveldb/util/env.cc | 96 + src/leveldb/util/env_posix.cc | 825 ++++ src/leveldb/util/env_test.cc | 104 + src/leveldb/util/env_win.cc | 1031 +++++ src/leveldb/util/filter_policy.cc | 11 + src/leveldb/util/hash.cc | 52 + src/leveldb/util/hash.h | 19 + src/leveldb/util/histogram.cc | 139 + src/leveldb/util/histogram.h | 42 + src/leveldb/util/logging.cc | 81 + src/leveldb/util/logging.h | 47 + src/leveldb/util/mutexlock.h | 41 + src/leveldb/util/options.cc | 29 + src/leveldb/util/posix_logger.h | 98 + src/leveldb/util/random.h | 64 + src/leveldb/util/status.cc | 75 + src/leveldb/util/testharness.cc | 77 + src/leveldb/util/testharness.h | 138 + src/leveldb/util/testutil.cc | 51 + src/leveldb/util/testutil.h | 53 + src/limitedmap.h | 100 + src/main.cpp | 3814 +++++++++++------ src/main.h | 1713 +++++--- src/makefile.linux-mingw | 74 +- src/makefile.mingw | 111 +- src/makefile.osx | 72 +- src/makefile.unix | 69 +- src/mruset.h | 1 - src/net.cpp | 1089 +++-- src/net.h | 386 +- src/netbase.cpp | 142 +- src/netbase.h | 20 +- src/noui.cpp | 35 +- src/obj-test/.gitignore | 2 + src/protocol.cpp | 6 +- src/protocol.h | 15 +- src/qt/aboutdialog.cpp | 11 +- src/qt/aboutdialog.h | 1 + src/qt/addressbookpage.cpp | 113 +- src/qt/addressbookpage.h | 37 +- src/qt/addresstablemodel.cpp | 38 +- src/qt/addresstablemodel.h | 24 +- src/qt/askpassphrasedialog.cpp | 27 +- src/qt/askpassphrasedialog.h | 3 +- src/qt/bitcoin.cpp | 190 +- src/qt/bitcoin.qrc | 19 +- src/qt/bitcoinaddressvalidator.cpp | 4 +- src/qt/bitcoinaddressvalidator.h | 11 +- src/qt/bitcoinamountfield.cpp | 15 +- src/qt/bitcoinamountfield.h | 13 +- src/qt/bitcoingui.cpp | 802 ++-- src/qt/bitcoingui.h | 98 +- src/qt/bitcoinstrings.cpp | 128 +- src/qt/bitcoinunits.cpp | 2 +- src/qt/bitcoinunits.h | 9 +- src/qt/clientmodel.cpp | 94 +- src/qt/clientmodel.h | 24 +- src/qt/coincontroldialog.cpp | 773 ++++ src/qt/coincontroldialog.h | 92 + src/qt/coincontroltreewidget.cpp | 28 + src/qt/coincontroltreewidget.h | 17 + src/qt/csvmodelwriter.h | 6 +- src/qt/editaddressdialog.cpp | 31 +- src/qt/editaddressdialog.h | 16 +- src/qt/forms/aboutdialog.ui | 36 +- src/qt/forms/addressbookpage.ui | 31 +- src/qt/forms/coincontroldialog.ui | 556 +++ src/qt/forms/optionsdialog.ui | 64 +- src/qt/forms/overviewpage.ui | 568 +-- src/qt/forms/rpcconsole.ui | 9 +- src/qt/forms/sendcoinsdialog.ui | 613 ++- src/qt/forms/sendcoinsentry.ui | 26 +- src/qt/forms/signverifymessagedialog.ui | 22 +- src/qt/guiconstants.h | 2 +- src/qt/guiutil.cpp | 124 +- src/qt/guiutil.h | 17 +- src/qt/locale/bitcoin_af_ZA.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_ar.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_bg.ts | 3254 ++++++++------ src/qt/locale/bitcoin_bs.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_ca.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_ca_ES.ts | 3618 +++++++++------- src/qt/locale/bitcoin_cs.ts | 3034 +++++++------ src/qt/locale/bitcoin_cy.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_da.ts | 3282 +++++++------- src/qt/locale/bitcoin_de.ts | 2949 +++++++------ src/qt/locale/bitcoin_el_GR.ts | 3104 ++++++++------ src/qt/locale/bitcoin_en.ts | 2693 ++++++++---- src/qt/locale/bitcoin_eo.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_es.ts | 3127 ++++++++------ src/qt/locale/bitcoin_es_CL.ts | 2890 +++++++------ src/qt/locale/bitcoin_et.ts | 3626 +++++++++------- src/qt/locale/bitcoin_eu_ES.ts | 3440 ++++++++------- src/qt/locale/bitcoin_fa.ts | 3301 +++++++------- src/qt/locale/bitcoin_fa_IR.ts | 3538 ++++++++------- src/qt/locale/bitcoin_fi.ts | 3001 +++++++------ src/qt/locale/bitcoin_fr.ts | 3114 ++++++++------ src/qt/locale/bitcoin_fr_CA.ts | 3117 ++++++++------ src/qt/locale/bitcoin_gu_IN.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_he.ts | 2988 +++++++------ src/qt/locale/bitcoin_hi_IN.ts | 2922 +++++++++++++ src/qt/locale/bitcoin_hr.ts | 3171 ++++++++------ src/qt/locale/bitcoin_hu.ts | 2988 +++++++------ src/qt/locale/bitcoin_it.ts | 2984 +++++++------ src/qt/locale/bitcoin_ja.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_la.ts | 2937 +++++++++++++ src/qt/locale/bitcoin_lt.ts | 3402 ++++++++------- src/qt/locale/bitcoin_lv_LV.ts | 2923 +++++++++++++ src/qt/locale/bitcoin_nb.ts | 2983 +++++++------ src/qt/locale/bitcoin_nl.ts | 2914 +++++++------ src/qt/locale/bitcoin_pl.ts | 2955 +++++++------ src/qt/locale/bitcoin_pt_BR.ts | 3368 ++++++++------- src/qt/locale/bitcoin_pt_PT.ts | 3018 +++++++------ src/qt/locale/bitcoin_ro_RO.ts | 3362 ++++++++------- src/qt/locale/bitcoin_ru.ts | 3125 ++++++++------ src/qt/locale/bitcoin_sk.ts | 3191 ++++++++------ src/qt/locale/bitcoin_sr.ts | 3359 ++++++++------- src/qt/locale/bitcoin_sv.ts | 2965 +++++++------ src/qt/locale/bitcoin_th_TH.ts | 2917 +++++++++++++ src/qt/locale/bitcoin_tr.ts | 2908 +++++++------ src/qt/locale/bitcoin_uk.ts | 3384 ++++++++------- src/qt/locale/bitcoin_zh_CN.ts | 2887 +++++++------ src/qt/locale/bitcoin_zh_TW.ts | 2922 +++++++------ src/qt/macdockiconhandler.h | 12 +- src/qt/macdockiconhandler.mm | 54 +- src/qt/macnotificationhandler.h | 25 + src/qt/macnotificationhandler.mm | 65 + src/qt/monitoreddatamapper.cpp | 1 - src/qt/monitoreddatamapper.h | 5 +- src/qt/notificator.cpp | 59 +- src/qt/notificator.h | 22 +- src/qt/optionsdialog.cpp | 139 +- src/qt/optionsdialog.h | 9 +- src/qt/optionsmodel.cpp | 156 +- src/qt/optionsmodel.h | 15 +- src/qt/overviewpage.cpp | 43 +- src/qt/overviewpage.h | 17 +- src/qt/paymentserver.cpp | 162 + src/qt/paymentserver.h | 67 + src/qt/qrcodedialog.cpp | 2 + src/qt/qvalidatedlineedit.h | 1 + src/qt/qvaluecombobox.h | 4 +- src/qt/res/bitcoin-qt.rc | 38 + src/qt/res/icons/bitcoin_testnet.ico | Bin 0 -> 370070 bytes src/qt/res/icons/casinocoin.icns | Bin 0 -> 104142 bytes src/qt/res/images/splash.png | Bin 0 -> 246711 bytes src/qt/res/images/splash_testnet.png | Bin 0 -> 149951 bytes src/qt/res/images/wallet.png | Bin 63960 -> 63665 bytes src/qt/res/src/bitcoin.svg | 169 +- src/qt/rpcconsole.cpp | 192 +- src/qt/sendcoinsdialog.cpp | 253 +- src/qt/sendcoinsdialog.h | 17 +- src/qt/sendcoinsentry.cpp | 11 +- src/qt/sendcoinsentry.h | 4 +- src/qt/signverifymessagedialog.cpp | 22 +- src/qt/signverifymessagedialog.h | 7 +- src/qt/splashscreen.cpp | 52 + src/qt/splashscreen.h | 16 + src/qt/test/test_main.cpp | 7 +- src/qt/test/uritests.cpp | 47 +- src/qt/transactiondesc.cpp | 26 +- src/qt/transactiondesc.h | 3 +- src/qt/transactiondescdialog.h | 1 + src/qt/transactionfilterproxy.cpp | 1 + src/qt/transactionfilterproxy.h | 9 +- src/qt/transactionrecord.cpp | 28 +- src/qt/transactionrecord.h | 8 +- src/qt/transactiontablemodel.cpp | 9 +- src/qt/transactiontablemodel.h | 5 +- src/qt/transactionview.cpp | 42 +- src/qt/transactionview.h | 2 + src/qt/walletframe.cpp | 161 + src/qt/walletframe.h | 77 + src/qt/walletmodel.cpp | 101 +- src/qt/walletmodel.h | 31 +- src/qt/walletstack.cpp | 161 + src/qt/walletstack.h | 103 + src/qt/walletview.cpp | 275 ++ src/qt/walletview.h | 108 + src/rpcblockchain.cpp | 270 ++ src/rpcdump.cpp | 49 +- src/rpcmining.cpp | 588 +++ src/rpcnet.cpp | 149 +- src/rpcrawtransaction.cpp | 342 +- src/rpcwallet.cpp | 1609 +++++++ src/script.cpp | 440 +- src/script.h | 103 +- src/scrypt-sse2.cpp | 136 + src/scrypt.cpp | 329 ++ src/scrypt.h | 44 +- src/serialize.h | 315 +- src/sync.cpp | 4 +- src/sync.h | 71 +- src/test/DoS_tests.cpp | 47 +- src/test/accounting_tests.cpp | 123 + src/test/alert_tests.cpp | 182 + src/test/allocator_tests.cpp | 115 + src/test/base58_tests.cpp | 304 +- src/test/bignum_tests.cpp | 59 +- src/test/bloom_tests.cpp | 446 ++ src/test/canonical_tests.cpp | 87 + src/test/checkblock_tests.cpp | 66 + src/test/compress_tests.cpp | 62 + src/test/data/alertTests | Bin 0 -> 1284 bytes src/test/data/base58_encode_decode.json | 14 + src/test/data/base58_keys_invalid.json | 152 + src/test/data/base58_keys_valid.json | 452 ++ src/test/data/script_invalid.json | 157 +- src/test/data/script_valid.json | 177 +- src/test/data/sig_canonical.json | 7 + src/test/data/sig_noncanonical.json | 22 + src/test/data/tx_invalid.json | 69 + src/test/data/tx_valid.json | 81 + src/test/key_tests.cpp | 92 +- src/test/miner_tests.cpp | 194 + src/test/multisig_tests.cpp | 28 +- src/test/netbase_tests.cpp | 26 +- src/test/pmt_tests.cpp | 98 + src/test/rpc_tests.cpp | 122 +- src/test/script_P2SH_tests.cpp | 53 +- src/test/script_tests.cpp | 54 +- src/test/scrypt_tests.cpp | 33 + src/test/serialize_tests.cpp | 45 + src/test/sigopcount_tests.cpp | 26 +- src/test/test_bitcoin.cpp | 34 +- src/test/transaction_tests.cpp | 212 +- src/test/util_tests.cpp | 51 +- src/test/wallet_tests.cpp | 51 +- src/threadsafety.h | 53 + src/txdb.cpp | 243 ++ src/txdb.h | 53 + src/ui_interface.h | 72 +- src/uint256.h | 31 +- src/util.cpp | 365 +- src/util.h | 389 +- src/version.cpp | 7 +- src/version.h | 22 +- src/wallet.cpp | 626 ++- src/wallet.h | 180 +- src/walletdb.cpp | 574 ++- src/walletdb.h | 51 +- 481 files changed, 156398 insertions(+), 57772 deletions(-) create mode 100644 .cproject create mode 100644 .project create mode 100644 contrib/debian/README create mode 100644 contrib/debian/bin/.svn/entries create mode 100644 contrib/debian/bin/.svn/text-base/bitcoind.svn-base create mode 100644 contrib/debian/manpages/bitcoin-qt.1 create mode 100644 contrib/gitian-downloader/aspect-key.pgp create mode 100644 contrib/gitian-downloader/coblee-key.pgp create mode 100644 contrib/gitian-downloader/face-key.pgp create mode 100644 contrib/gitian-downloader/thrasher-key.pgp create mode 100644 contrib/gitian-downloader/wtogami-key.pgp create mode 100644 contrib/seeds/README create mode 100644 contrib/seeds/makeseeds.py create mode 100644 contrib/spendfrom/README create mode 100644 contrib/spendfrom/setup.py create mode 100644 contrib/spendfrom/spendfrom.py create mode 100644 contrib/test-patches/README create mode 100644 contrib/testgen/README create mode 100644 contrib/testgen/base58.py create mode 100644 contrib/testgen/gen_base58_test_vectors.py create mode 100644 contrib/tidy_datadir.sh create mode 100644 contrib/wallettools/.svn/entries create mode 100644 contrib/wallettools/.svn/text-base/walletchangepass.py.svn-base create mode 100644 contrib/wallettools/.svn/text-base/walletunlock.py.svn-base create mode 100644 doc/README.md create mode 100644 doc/build-msw.md create mode 100644 doc/build-osx.md create mode 100644 doc/build-unix.md create mode 100644 doc/coding.md create mode 100644 doc/files.txt create mode 100644 doc/multiwallet-qt.md create mode 100644 doc/release-notes.md create mode 100644 doc/release-process.md create mode 100644 doc/unit-tests.md create mode 100644 share/certs/BitcoinFoundation_Apple_Cert.pem create mode 100644 share/certs/BitcoinFoundation_Comodo_Cert.pem create mode 100644 share/certs/PrivateKeyNotes.md create mode 100644 share/pixmaps/bitcoin128.png create mode 100644 share/pixmaps/bitcoin128.xpm create mode 100644 share/pixmaps/bitcoin16.png create mode 100644 share/pixmaps/bitcoin16.xpm create mode 100644 share/pixmaps/bitcoin256.png create mode 100644 share/pixmaps/bitcoin256.xpm create mode 100644 share/pixmaps/bitcoin32.png create mode 100644 share/pixmaps/bitcoin64.png create mode 100644 share/pixmaps/bitcoin64.xpm create mode 100644 share/qt/Info.plist create mode 100644 share/qt/clean_mac_info_plist.py create mode 100644 src/alert.cpp create mode 100644 src/alert.h create mode 100644 src/bloom.cpp create mode 100644 src/bloom.h create mode 100644 src/checkqueue.h create mode 100644 src/clientversion.h create mode 100644 src/coincontrol.h create mode 100644 src/hash.cpp create mode 100644 src/hash.h create mode 100644 src/leveldb.cpp create mode 100644 src/leveldb.h create mode 100644 src/leveldb/.gitignore create mode 100644 src/leveldb/AUTHORS create mode 100644 src/leveldb/LICENSE create mode 100644 src/leveldb/NEWS create mode 100644 src/leveldb/README create mode 100644 src/leveldb/TODO create mode 100644 src/leveldb/WINDOWS.md create mode 100644 src/leveldb/build_detect_platform create mode 100644 src/leveldb/db/autocompact_test.cc create mode 100644 src/leveldb/db/builder.cc create mode 100644 src/leveldb/db/builder.h create mode 100644 src/leveldb/db/c.cc create mode 100644 src/leveldb/db/c_test.c create mode 100644 src/leveldb/db/corruption_test.cc create mode 100644 src/leveldb/db/db_bench.cc create mode 100644 src/leveldb/db/db_impl.cc create mode 100644 src/leveldb/db/db_impl.h create mode 100644 src/leveldb/db/db_iter.cc create mode 100644 src/leveldb/db/db_iter.h create mode 100644 src/leveldb/db/db_test.cc create mode 100644 src/leveldb/db/dbformat.cc create mode 100644 src/leveldb/db/dbformat.h create mode 100644 src/leveldb/db/dbformat_test.cc create mode 100644 src/leveldb/db/filename.cc create mode 100644 src/leveldb/db/filename.h create mode 100644 src/leveldb/db/filename_test.cc create mode 100644 src/leveldb/db/leveldb_main.cc create mode 100644 src/leveldb/db/log_format.h create mode 100644 src/leveldb/db/log_reader.cc create mode 100644 src/leveldb/db/log_reader.h create mode 100644 src/leveldb/db/log_test.cc create mode 100644 src/leveldb/db/log_writer.cc create mode 100644 src/leveldb/db/log_writer.h create mode 100644 src/leveldb/db/memtable.cc create mode 100644 src/leveldb/db/memtable.h create mode 100644 src/leveldb/db/repair.cc create mode 100644 src/leveldb/db/skiplist.h create mode 100644 src/leveldb/db/skiplist_test.cc create mode 100644 src/leveldb/db/snapshot.h create mode 100644 src/leveldb/db/table_cache.cc create mode 100644 src/leveldb/db/table_cache.h create mode 100644 src/leveldb/db/version_edit.cc create mode 100644 src/leveldb/db/version_edit.h create mode 100644 src/leveldb/db/version_edit_test.cc create mode 100644 src/leveldb/db/version_set.cc create mode 100644 src/leveldb/db/version_set.h create mode 100644 src/leveldb/db/version_set_test.cc create mode 100644 src/leveldb/db/write_batch.cc create mode 100644 src/leveldb/db/write_batch_internal.h create mode 100644 src/leveldb/db/write_batch_test.cc create mode 100644 src/leveldb/doc/bench/db_bench_sqlite3.cc create mode 100644 src/leveldb/doc/bench/db_bench_tree_db.cc create mode 100644 src/leveldb/doc/benchmark.html create mode 100644 src/leveldb/doc/doc.css create mode 100644 src/leveldb/doc/impl.html create mode 100644 src/leveldb/doc/index.html create mode 100644 src/leveldb/doc/log_format.txt create mode 100644 src/leveldb/doc/table_format.txt create mode 100644 src/leveldb/helpers/memenv/memenv.cc create mode 100644 src/leveldb/helpers/memenv/memenv.h create mode 100644 src/leveldb/helpers/memenv/memenv_test.cc create mode 100644 src/leveldb/include/leveldb/c.h create mode 100644 src/leveldb/include/leveldb/cache.h create mode 100644 src/leveldb/include/leveldb/comparator.h create mode 100644 src/leveldb/include/leveldb/db.h create mode 100644 src/leveldb/include/leveldb/env.h create mode 100644 src/leveldb/include/leveldb/filter_policy.h create mode 100644 src/leveldb/include/leveldb/iterator.h create mode 100644 src/leveldb/include/leveldb/options.h create mode 100644 src/leveldb/include/leveldb/slice.h create mode 100644 src/leveldb/include/leveldb/status.h create mode 100644 src/leveldb/include/leveldb/table.h create mode 100644 src/leveldb/include/leveldb/table_builder.h create mode 100644 src/leveldb/include/leveldb/write_batch.h create mode 100644 src/leveldb/issues/issue178_test.cc create mode 100644 src/leveldb/port/README create mode 100644 src/leveldb/port/atomic_pointer.h create mode 100644 src/leveldb/port/port.h create mode 100644 src/leveldb/port/port_example.h create mode 100644 src/leveldb/port/port_posix.cc create mode 100644 src/leveldb/port/port_posix.h create mode 100644 src/leveldb/port/port_win.cc create mode 100644 src/leveldb/port/port_win.h create mode 100644 src/leveldb/port/thread_annotations.h create mode 100644 src/leveldb/port/win/stdint.h create mode 100644 src/leveldb/table/block.cc create mode 100644 src/leveldb/table/block.h create mode 100644 src/leveldb/table/block_builder.cc create mode 100644 src/leveldb/table/block_builder.h create mode 100644 src/leveldb/table/filter_block.cc create mode 100644 src/leveldb/table/filter_block.h create mode 100644 src/leveldb/table/filter_block_test.cc create mode 100644 src/leveldb/table/format.cc create mode 100644 src/leveldb/table/format.h create mode 100644 src/leveldb/table/iterator.cc create mode 100644 src/leveldb/table/iterator_wrapper.h create mode 100644 src/leveldb/table/merger.cc create mode 100644 src/leveldb/table/merger.h create mode 100644 src/leveldb/table/table.cc create mode 100644 src/leveldb/table/table_builder.cc create mode 100644 src/leveldb/table/table_test.cc create mode 100644 src/leveldb/table/two_level_iterator.cc create mode 100644 src/leveldb/table/two_level_iterator.h create mode 100644 src/leveldb/util/arena.cc create mode 100644 src/leveldb/util/arena.h create mode 100644 src/leveldb/util/arena_test.cc create mode 100644 src/leveldb/util/bloom.cc create mode 100644 src/leveldb/util/bloom_test.cc create mode 100644 src/leveldb/util/cache.cc create mode 100644 src/leveldb/util/cache_test.cc create mode 100644 src/leveldb/util/coding.cc create mode 100644 src/leveldb/util/coding.h create mode 100644 src/leveldb/util/coding_test.cc create mode 100644 src/leveldb/util/comparator.cc create mode 100644 src/leveldb/util/crc32c.cc create mode 100644 src/leveldb/util/crc32c.h create mode 100644 src/leveldb/util/crc32c_test.cc create mode 100644 src/leveldb/util/env.cc create mode 100644 src/leveldb/util/env_posix.cc create mode 100644 src/leveldb/util/env_test.cc create mode 100644 src/leveldb/util/env_win.cc create mode 100644 src/leveldb/util/filter_policy.cc create mode 100644 src/leveldb/util/hash.cc create mode 100644 src/leveldb/util/hash.h create mode 100644 src/leveldb/util/histogram.cc create mode 100644 src/leveldb/util/histogram.h create mode 100644 src/leveldb/util/logging.cc create mode 100644 src/leveldb/util/logging.h create mode 100644 src/leveldb/util/mutexlock.h create mode 100644 src/leveldb/util/options.cc create mode 100644 src/leveldb/util/posix_logger.h create mode 100644 src/leveldb/util/random.h create mode 100644 src/leveldb/util/status.cc create mode 100644 src/leveldb/util/testharness.cc create mode 100644 src/leveldb/util/testharness.h create mode 100644 src/leveldb/util/testutil.cc create mode 100644 src/leveldb/util/testutil.h create mode 100644 src/limitedmap.h create mode 100644 src/obj-test/.gitignore create mode 100644 src/qt/coincontroldialog.cpp create mode 100644 src/qt/coincontroldialog.h create mode 100644 src/qt/coincontroltreewidget.cpp create mode 100644 src/qt/coincontroltreewidget.h create mode 100644 src/qt/forms/coincontroldialog.ui create mode 100644 src/qt/locale/bitcoin_af_ZA.ts create mode 100644 src/qt/locale/bitcoin_ar.ts create mode 100644 src/qt/locale/bitcoin_bs.ts create mode 100644 src/qt/locale/bitcoin_ca.ts create mode 100644 src/qt/locale/bitcoin_cy.ts create mode 100644 src/qt/locale/bitcoin_eo.ts create mode 100644 src/qt/locale/bitcoin_gu_IN.ts create mode 100644 src/qt/locale/bitcoin_hi_IN.ts create mode 100644 src/qt/locale/bitcoin_ja.ts create mode 100644 src/qt/locale/bitcoin_la.ts create mode 100644 src/qt/locale/bitcoin_lv_LV.ts create mode 100644 src/qt/locale/bitcoin_th_TH.ts create mode 100644 src/qt/macnotificationhandler.h create mode 100644 src/qt/macnotificationhandler.mm create mode 100644 src/qt/paymentserver.cpp create mode 100644 src/qt/paymentserver.h create mode 100644 src/qt/res/icons/bitcoin_testnet.ico create mode 100644 src/qt/res/icons/casinocoin.icns create mode 100644 src/qt/res/images/splash.png create mode 100644 src/qt/res/images/splash_testnet.png create mode 100644 src/qt/splashscreen.cpp create mode 100644 src/qt/splashscreen.h create mode 100644 src/qt/walletframe.cpp create mode 100644 src/qt/walletframe.h create mode 100644 src/qt/walletstack.cpp create mode 100644 src/qt/walletstack.h create mode 100644 src/qt/walletview.cpp create mode 100644 src/qt/walletview.h create mode 100644 src/rpcblockchain.cpp create mode 100644 src/rpcmining.cpp create mode 100644 src/rpcwallet.cpp create mode 100644 src/scrypt-sse2.cpp create mode 100644 src/scrypt.cpp create mode 100644 src/test/accounting_tests.cpp create mode 100644 src/test/alert_tests.cpp create mode 100644 src/test/allocator_tests.cpp create mode 100644 src/test/bloom_tests.cpp create mode 100644 src/test/canonical_tests.cpp create mode 100644 src/test/checkblock_tests.cpp create mode 100644 src/test/compress_tests.cpp create mode 100644 src/test/data/alertTests create mode 100644 src/test/data/base58_encode_decode.json create mode 100644 src/test/data/base58_keys_invalid.json create mode 100644 src/test/data/base58_keys_valid.json create mode 100644 src/test/data/sig_canonical.json create mode 100644 src/test/data/sig_noncanonical.json create mode 100644 src/test/data/tx_invalid.json create mode 100644 src/test/data/tx_valid.json create mode 100644 src/test/pmt_tests.cpp create mode 100644 src/test/scrypt_tests.cpp create mode 100644 src/test/serialize_tests.cpp create mode 100644 src/threadsafety.h create mode 100644 src/txdb.cpp create mode 100644 src/txdb.h diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..58ec76b --- /dev/null +++ b/.cproject @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index 20ef5ff..54c9a56 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ src/*.exe src/casinocoin src/casinocoind src/test_casinocoin -src/build.h .*.swp *.*~* *.bak @@ -10,24 +9,26 @@ src/build.h *.orig *.o *.patch -.bitcoin -#compilation and Qt preprocessor part +.casinocoin + +# Compilation and Qt preprocessor part *.qm Makefile casinocoin-qt -#resources cpp +CasinoCoin-Qt.app + +# Unit-tests +Makefile.test +casinocoin-qt_test + +# Resources cpp qrc_*.cpp -#qt creator + +# Qt creator *.pro.user -#mac specific + +# Mac specific .DS_Store build -.cproject -.project -debug -release -.svn -object_script.casinocoin-qt.Debug -object_script.casinocoin-qt.Release -object_script.litecoin-qt.Debug -object_script.litecoin-qt.Release + +!src/leveldb-*/Makefile diff --git a/.project b/.project new file mode 100644 index 0000000..3863fe1 --- /dev/null +++ b/.project @@ -0,0 +1,27 @@ + + + csc + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/COPYING b/COPYING index a7dd716..2fe1792 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,5 @@ -Copyright (c) 2009-2012 Bitcoin Developers -Copyright (c) 2011-2012 Litecoin Developers -Copyright (c) 2013 CasinoCoin Developers +Copyright (c) 2009-2013 Bitcoin Developers +Copyright (c) 2011-2013 CasinoCoin 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 index c1866de..b183c00 100644 --- a/INSTALL +++ b/INSTALL @@ -1,6 +1,6 @@ Building CasinoCoin -See doc/readme-qt.rst for instructions on building CasinoCoin-QT, +See doc/readme-qt.rst for instructions on building CasinoCoin-Qt, the intended-for-end-users, nice-graphical-interface, reference implementation of CasinoCoin. diff --git a/casinocoin-qt.pro b/casinocoin-qt.pro index 315ea3e..6297980 100644 --- a/casinocoin-qt.pro +++ b/casinocoin-qt.pro @@ -1,9 +1,13 @@ TEMPLATE = app -TARGET = -VERSION = 1.0.0.4 +TARGET = casinocoin-qt +macx:TARGET = "CasinoCoin-Qt" +VERSION = 1.1.0.0 INCLUDEPATH += src src/json src/qt +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE USE_IPV6 __NO_SYSTEM_INCLUDES CONFIG += no_include_pwd +CONFIG += thread # for boost 1.37, add -mt to the boost libraries # use: qmake BOOST_LIB_SUFFIX=-mt @@ -21,6 +25,8 @@ BDB_INCLUDE_PATH=E:/crypto/deps/db-4.8.30.NC/build_unix BDB_LIB_PATH=E:/crypto/deps/db-4.8.30.NC/build_unix OPENSSL_INCLUDE_PATH=E:/crypto/deps/openssl-1.0.1b/include OPENSSL_LIB_PATH=E:/crypto/deps/openssl-1.0.1b +QRENCODE_INCLUDE_PATH=E:/crypto/deps/qrencode-3.4.3 +QRENCODE_LIB_PATH=E:/crypto/deps/qrencode-3.4.3/.libs OBJECTS_DIR = build MOC_DIR = build @@ -31,20 +37,37 @@ contains(RELEASE, 1) { # Mac: compile for maximum compatibility (10.5, 32-bit) macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk macx:QMAKE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - macx:QMAKE_LFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - !windows:!macx { - # Linux: static link - LIBS += -Wl,-Bstatic + !win32:!macx { + # Linux: static link and extra security (see: https://wiki.debian.org/Hardening) + LIBS += -Wl,-Bstatic -Wl,-z,relro -Wl,-z,now } } +!win32 { + # for extra security against potential buffer overflows: enable GCCs Stack Smashing Protection + QMAKE_CXXFLAGS *= -fstack-protector-all + QMAKE_LFLAGS *= -fstack-protector-all + # Exclude on Windows cross compile with MinGW 4.2.x, as it will result in a non-working executable! + # This can be enabled for Windows, when we switch to MinGW >= 4.4.x. +} +# for extra security (see: https://wiki.debian.org/Hardening): this flag is GCC compiler-specific +QMAKE_CXXFLAGS *= -D_FORTIFY_SOURCE=2 +# for extra security on Windows: enable ASLR and DEP via GCC linker flags +win32:QMAKE_LFLAGS *= -Wl,--dynamicbase -Wl,--nxcompat +# on Windows: enable GCC large address aware linker flag +win32:QMAKE_LFLAGS *= -Wl,--large-address-aware +# i686-w64-mingw32 +win32:QMAKE_LFLAGS *= -static-libgcc -static-libstdc++ + # use: qmake "USE_QRCODE=1" # libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support contains(USE_QRCODE, 1) { message(Building with QRCode support) DEFINES += USE_QRCODE - LIBS += -lqrencode + #LIBS += -lqrencode + LIBS += -lqrencode $$join(QRENCODE_LIB_PATH,,-L,) } # use: qmake "USE_UPNP=1" ( enabled by default; default) @@ -71,10 +94,16 @@ contains(USE_DBUS, 1) { QT += dbus } -# use: qmake "FIRST_CLASS_MESSAGING=1" -contains(FIRST_CLASS_MESSAGING, 1) { - message(Building with first-class messaging) - DEFINES += FIRST_CLASS_MESSAGING +# use: qmake "USE_IPV6=1" ( enabled by default; default) +# or: qmake "USE_IPV6=0" (disabled by default) +# or: qmake "USE_IPV6=-" (not supported) +contains(USE_IPV6, -) { + message(Building without IPv6 support) +} else { + count(USE_IPV6, 0) { + USE_IPV6=1 + } + DEFINES += USE_IPV6=$$USE_IPV6 } contains(BITCOIN_NEED_QT_PLUGINS, 1) { @@ -82,15 +111,28 @@ contains(BITCOIN_NEED_QT_PLUGINS, 1) { QTPLUGIN += qcncodecs qjpcodecs qtwcodecs qkrcodecs qtaccessiblewidgets } -!windows { - # for extra security against potential buffer overflows - QMAKE_CXXFLAGS += -fstack-protector - QMAKE_LFLAGS += -fstack-protector - # do not enable this on windows, as it will result in a non-working executable! +INCLUDEPATH += src/leveldb/include src/leveldb/helpers +LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a +!win32 { + # we use QMAKE_CXXFLAGS_RELEASE even without RELEASE=1 because we use RELEASE to indicate linking preferences not -O preferences + genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" libleveldb.a libmemenv.a +} else { + # make an educated guess about what the ranlib command is called + isEmpty(QMAKE_RANLIB) { + QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, ranlib) + } + LIBS += -lshlwapi + # genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" libleveldb.a libmemenv.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a } +genleveldb.target = $$PWD/src/leveldb/libleveldb.a +genleveldb.depends = FORCE +PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a +QMAKE_EXTRA_TARGETS += genleveldb +# Gross ugly hack that depends on qmake internals, unfortunately there is no other way to do it. +QMAKE_CLEAN += $$PWD/src/leveldb/libleveldb.a; cd $$PWD/src/leveldb ; $(MAKE) clean # regenerate src/build.h -!windows|contains(USE_BUILD_INFO, 1) { +!win32|contains(USE_BUILD_INFO, 1) { genbuild.depends = FORCE genbuild.commands = cd $$PWD; /bin/sh share/genbuild.sh $$OUT_PWD/build/build.h genbuild.target = $$OUT_PWD/build/build.h @@ -99,7 +141,7 @@ contains(BITCOIN_NEED_QT_PLUGINS, 1) { DEFINES += HAVE_BUILD_INFO } -QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter +QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wstack-protector # Input DEPENDPATH += src src/json src/qt @@ -108,21 +150,25 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/addresstablemodel.h \ src/qt/optionsdialog.h \ src/qt/sendcoinsdialog.h \ + src/qt/coincontroldialog.h \ + src/qt/coincontroltreewidget.h \ src/qt/addressbookpage.h \ src/qt/signverifymessagedialog.h \ src/qt/aboutdialog.h \ src/qt/editaddressdialog.h \ src/qt/bitcoinaddressvalidator.h \ + src/alert.h \ src/addrman.h \ src/base58.h \ src/bignum.h \ src/checkpoints.h \ + src/coincontrol.h \ src/compat.h \ src/sync.h \ src/util.h \ + src/hash.h \ src/uint256.h \ src/serialize.h \ - src/strlcpy.h \ src/main.h \ src/net.h \ src/key.h \ @@ -130,8 +176,9 @@ HEADERS += src/qt/bitcoingui.h \ src/walletdb.h \ src/script.h \ src/init.h \ - src/irc.h \ + src/bloom.h \ src/mruset.h \ + src/checkqueue.h \ src/json/json_spirit_writer_template.h \ src/json/json_spirit_writer.h \ src/json/json_spirit_value.h \ @@ -155,6 +202,9 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/transactionfilterproxy.h \ src/qt/transactionview.h \ src/qt/walletmodel.h \ + src/qt/walletview.h \ + src/qt/walletstack.h \ + src/qt/walletframe.h \ src/bitcoinrpc.h \ src/qt/overviewpage.h \ src/qt/csvmodelwriter.h \ @@ -166,40 +216,50 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/askpassphrasedialog.h \ src/protocol.h \ src/qt/notificator.h \ - src/qt/qtipcserver.h \ + src/qt/paymentserver.h \ src/allocators.h \ src/ui_interface.h \ + src/qt/rpcconsole.h \ src/scrypt.h \ src/version.h \ - src/qt/rpcconsole.h + src/netbase.h \ + src/clientversion.h \ + src/txdb.h \ + src/leveldb.h \ + src/threadsafety.h \ + src/limitedmap.h \ + src/qt/macnotificationhandler.h \ + src/qt/splashscreen.h -SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ +SOURCES += src/qt/bitcoin.cpp \ + src/qt/bitcoingui.cpp \ src/qt/transactiontablemodel.cpp \ src/qt/addresstablemodel.cpp \ src/qt/optionsdialog.cpp \ src/qt/sendcoinsdialog.cpp \ + src/qt/coincontroldialog.cpp \ + src/qt/coincontroltreewidget.cpp \ src/qt/addressbookpage.cpp \ src/qt/signverifymessagedialog.cpp \ src/qt/aboutdialog.cpp \ src/qt/editaddressdialog.cpp \ src/qt/bitcoinaddressvalidator.cpp \ + src/alert.cpp \ src/version.cpp \ src/sync.cpp \ src/util.cpp \ + src/hash.cpp \ src/netbase.cpp \ src/key.cpp \ src/script.cpp \ src/main.cpp \ src/init.cpp \ src/net.cpp \ - src/irc.cpp \ + src/bloom.cpp \ src/checkpoints.cpp \ src/addrman.cpp \ src/db.cpp \ src/walletdb.cpp \ - src/json/json_spirit_writer.cpp \ - src/json/json_spirit_value.cpp \ - src/json/json_spirit_reader.cpp \ src/qt/clientmodel.cpp \ src/qt/guiutil.cpp \ src/qt/transactionrecord.cpp \ @@ -214,9 +274,15 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/transactionfilterproxy.cpp \ src/qt/transactionview.cpp \ src/qt/walletmodel.cpp \ + src/qt/walletview.cpp \ + src/qt/walletstack.cpp \ + src/qt/walletframe.cpp \ src/bitcoinrpc.cpp \ src/rpcdump.cpp \ src/rpcnet.cpp \ + src/rpcmining.cpp \ + src/rpcwallet.cpp \ + src/rpcblockchain.cpp \ src/rpcrawtransaction.cpp \ src/qt/overviewpage.cpp \ src/qt/csvmodelwriter.cpp \ @@ -228,16 +294,18 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/askpassphrasedialog.cpp \ src/protocol.cpp \ src/qt/notificator.cpp \ - src/qt/qtipcserver.cpp \ + src/qt/paymentserver.cpp \ src/qt/rpcconsole.cpp \ - src/scrypt.c \ - src/noui.cpp + src/scrypt.cpp \ + src/noui.cpp \ + src/leveldb.cpp \ + src/txdb.cpp \ + src/qt/splashscreen.cpp -RESOURCES += \ - src/qt/bitcoin.qrc +RESOURCES += src/qt/bitcoin.qrc -FORMS += \ - src/qt/forms/sendcoinsdialog.ui \ +FORMS += src/qt/forms/sendcoinsdialog.ui \ + src/qt/forms/coincontroldialog.ui \ src/qt/forms/addressbookpage.ui \ src/qt/forms/signverifymessagedialog.ui \ src/qt/forms/aboutdialog.ui \ @@ -261,10 +329,21 @@ SOURCES += src/qt/test/test_main.cpp \ HEADERS += src/qt/test/uritests.h DEPENDPATH += src/qt/test QT += testlib -TARGET = bitcoin-qt_test +TARGET = casinocoin-qt_test DEFINES += BITCOIN_QT_TEST + macx: CONFIG -= app_bundle } +contains(USE_SSE2, 1) { +DEFINES += USE_SSE2 +gccsse2.input = SOURCES_SSE2 +gccsse2.output = $$PWD/build/${QMAKE_FILE_BASE}.o +gccsse2.commands = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -msse2 -mstackrealign +QMAKE_EXTRA_COMPILERS += gccsse2 +SOURCES_SSE2 += src/scrypt-sse2.cpp +} + +# Todo: Remove this line when switching to Qt5, as that option was removed CODECFORTR = UTF-8 # for lrelease/lupdate @@ -285,14 +364,20 @@ TSQM.CONFIG = no_link QMAKE_EXTRA_COMPILERS += TSQM # "Other files" to show in Qt Creator -OTHER_FILES += \ - contrib/gitian-descriptors/* doc/*.rst doc/*.txt doc/README README.md res/bitcoin-qt.rc \ - share/setup.nsi +OTHER_FILES += README.md \ + doc/*.rst \ + doc/*.txt \ + doc/*.md \ + src/qt/res/bitcoin-qt.rc \ + src/test/*.cpp \ + src/test/*.h \ + src/qt/test/*.cpp \ + src/qt/test/*.h # platform specific defaults, if not overridden on command line isEmpty(BOOST_LIB_SUFFIX) { macx:BOOST_LIB_SUFFIX = -mt - windows:BOOST_LIB_SUFFIX = -mgw46-mt-s-1_53 + win32:BOOST_LIB_SUFFIX = -mgw46-mt-s-1_53 } isEmpty(BOOST_THREAD_LIB_SUFFIX) { @@ -319,11 +404,10 @@ isEmpty(BOOST_INCLUDE_PATH) { macx:BOOST_INCLUDE_PATH = /opt/local/include } -windows:LIBS += -lshlwapi -windows:DEFINES += WIN32 -windows:RC_FILE = src/qt/res/bitcoin-qt.rc +win32:DEFINES += WIN32 +win32:RC_FILE = src/qt/res/bitcoin-qt.rc -windows:!contains(MINGW_THREAD_BUGFIX, 0) { +win32:!contains(MINGW_THREAD_BUGFIX, 0) { # At least qmake's win32-g++-cross profile is missing the -lmingwthrd # thread-safety flag. GCC has -mthreads to enable this, but it doesn't # work with static linking. -lmingwthrd must come BEFORE -lmingw, so @@ -334,33 +418,38 @@ windows:!contains(MINGW_THREAD_BUGFIX, 0) { QMAKE_LIBS_QT_ENTRY = -lmingwthrd $$QMAKE_LIBS_QT_ENTRY } -!windows:!mac { +!win32:!macx { DEFINES += LINUX LIBS += -lrt + # _FILE_OFFSET_BITS=64 lets 32-bit fopen transparently support large files. + DEFINES += _FILE_OFFSET_BITS=64 } -macx:HEADERS += src/qt/macdockiconhandler.h -macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm -macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit +macx:HEADERS += src/qt/macdockiconhandler.h src/qt/macnotificationhandler.h +macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm src/qt/macnotificationhandler.mm +macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit -framework CoreServices macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 -macx:ICON = src/qt/res/icons/bitcoin.icns -macx:TARGET = "CasinoCoin-Qt" +macx:ICON = src/qt/res/icons/casinocoin.icns +macx:QMAKE_CFLAGS_THREAD += -pthread +macx:QMAKE_LFLAGS_THREAD += -pthread +macx:QMAKE_CXXFLAGS_THREAD += -pthread +macx:QMAKE_INFO_PLIST = share/qt/Info.plist # Set libraries and includes at end, to use platform-defined defaults if not overridden INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH $$QRENCODE_INCLUDE_PATH LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB_PATH,,-L,) $$join(QRENCODE_LIB_PATH,,-L,) -LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX +LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX -lpthread # -lgdi32 has to happen after -lcrypto (see #681) -windows:LIBS += -lws2_32 -lole32 -lmswsock -loleaut32 -luuid -lgdi32 +win32:LIBS += -lws2_32 -lole32 -lmswsock -loleaut32 -luuid -lgdi32 -lshlwapi LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX +win32:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX +macx:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX contains(RELEASE, 1) { - !windows:!macx { + !win32:!macx { # Linux: turn dynamic linking back on for c/c++ runtime libraries LIBS += -Wl,-Bdynamic } } -system($$QMAKE_LRELEASE -silent $$_PRO_FILE_) - - +system($$QMAKE_LRELEASE -silent $$TRANSLATIONS) diff --git a/contrib/bitrpc/bitrpc.py b/contrib/bitrpc/bitrpc.py index b02b299..cf6a57e 100644 --- a/contrib/bitrpc/bitrpc.py +++ b/contrib/bitrpc/bitrpc.py @@ -10,9 +10,9 @@ rpcpass = "" if rpcpass == "": - access = ServiceProxy("http://127.0.0.1:8332") + access = ServiceProxy("http://127.0.0.1:47970") else: - access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:8332") + access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:47970") cmd = sys.argv[1].lower() if cmd == "backupwallet": @@ -24,7 +24,7 @@ if cmd == "backupwallet": elif cmd == "getaccount": try: - addr = raw_input("Enter a Bitcoin address: ") + addr = raw_input("Enter a CasinoCoin address: ") print access.getaccount(addr) except: print "\n---An error occurred---\n" @@ -126,7 +126,7 @@ elif cmd == "getreceivedbyaccount": elif cmd == "getreceivedbyaddress": try: - addr = raw_input("Enter a Bitcoin address (optional): ") + addr = raw_input("Enter a CasinoCoin address (optional): ") mc = raw_input("Minimum confirmations (optional): ") try: print access.getreceivedbyaddress(addr, mc) @@ -321,4 +321,4 @@ elif cmd == "walletpassphrasechange": print else: - print "Command not found or not supported" \ No newline at end of file + print "Command not found or not supported" diff --git a/contrib/debian/README b/contrib/debian/README new file mode 100644 index 0000000..1cb9b75 --- /dev/null +++ b/contrib/debian/README @@ -0,0 +1,20 @@ +This directory contains files used to package bitcoind/bitcoin-qt +for Debian-based Linux systems. + +If you compile bitcoind/bitcoin-qt yourself, there are some +useful files here: + +bitcoin: URI support +-------------------- + +bitcoin-qt.desktop (Gnome / Open Desktop) +To install: + sudo desktop-file-install bitcoin-qt.desktop + sudo update-desktop-database + +If you build yourself, you will either need to modify the paths in +the .desktop file or copy or symlink your bitcoin-qt binary to /usr/bin +and the ../../share/pixmaps/bitcoin128.png to /usr/share/pixmaps + +bitcoin-qt.protocol (KDE) + diff --git a/contrib/debian/bin/.svn/entries b/contrib/debian/bin/.svn/entries new file mode 100644 index 0000000..d994cf1 --- /dev/null +++ b/contrib/debian/bin/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +114 +svn://svn.greyhatapps.com/repos/projects/casinocoin/contrib/debian/bin +svn://svn.greyhatapps.com/repos/projects + + + +2013-07-03T07:48:00.318239Z +64 +nam + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +1324ab70-8081-43f4-a012-72ad25adf38d + +bitcoind +file + + + + +2013-06-25T14:29:02.000000Z +1e30c9a90444273ac9aa7a656a7b8948 +2013-07-03T07:48:00.318239Z +64 +nam + + + + + + + + + + + + + + + + + + + + + +258 + diff --git a/contrib/debian/bin/.svn/text-base/bitcoind.svn-base b/contrib/debian/bin/.svn/text-base/bitcoind.svn-base new file mode 100644 index 0000000..a2f55a9 --- /dev/null +++ b/contrib/debian/bin/.svn/text-base/bitcoind.svn-base @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +umask 077 + +basedir=~/.bitcoin +cfgfile="$basedir/bitcoin.conf" + +[ -e "$basedir" ] || mkdir "$basedir" + +[ -e "$cfgfile" ] || perl -le 'print"rpcpassword=",map{(a..z,A..Z,0..9)[rand 62]}0..9' > "$cfgfile" + +exec /usr/lib/bitcoin/bitcoind "$@" diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop index 7cb00a2..b2a2cef 100644 --- a/contrib/debian/bitcoin-qt.desktop +++ b/contrib/debian/bitcoin-qt.desktop @@ -4,9 +4,9 @@ Name=Bitcoin Comment=Bitcoin P2P Cryptocurrency Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi -Exec=/usr/bin/bitcoin-qt +Exec=/usr/bin/bitcoin-qt %u Terminal=false Type=Application -Icon=/usr/share/pixmaps/bitcoin80.xpm +Icon=/usr/share/pixmaps/bitcoin128.png MimeType=x-scheme-handler/bitcoin; Categories=Office; diff --git a/contrib/debian/bitcoin-qt.install b/contrib/debian/bitcoin-qt.install index ba40713..59cacb0 100644 --- a/contrib/debian/bitcoin-qt.install +++ b/contrib/debian/bitcoin-qt.install @@ -1,5 +1,6 @@ bitcoin-qt usr/bin share/pixmaps/bitcoin32.xpm usr/share/pixmaps -share/pixmaps/bitcoin80.xpm usr/share/pixmaps +share/pixmaps/bitcoin16.xpm usr/share/pixmaps +share/pixmaps/bitcoin128.png usr/share/pixmaps debian/bitcoin-qt.desktop usr/share/applications debian/bitcoin-qt.protocol usr/share/kde4/services/ diff --git a/contrib/debian/bitcoind.install b/contrib/debian/bitcoind.install index e978c44..7bf7460 100644 --- a/contrib/debian/bitcoind.install +++ b/contrib/debian/bitcoind.install @@ -1,2 +1 @@ -debian/bin/bitcoind usr/bin -src/bitcoind usr/lib/bitcoin +src/bitcoind usr/bin diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 52d0e59..e600e46 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,45 @@ +bitcoin (0.8.1-natty3) natty; urgency=low + + * New pixmaps + + -- Jonas Schnelli Mon, 13 May 2013 16:14:00 +0100 + +bitcoin (0.8.1-natty2) natty; urgency=low + + * Remove dumb broken launcher script + + -- Matt Corallo Sun, 24 Mar 2013 20:01:00 -0400 + +bitcoin (0.8.1-natty1) natty; urgency=low + + * New upstream release. + + -- Matt Corallo Tue, 19 Mar 2013 13:03:00 -0400 + +bitcoin (0.8.0-natty1) natty; urgency=low + + * New upstream release. + + -- Matt Corallo Sat, 23 Feb 2013 16:01:00 -0500 + +bitcoin (0.7.2-natty1) natty; urgency=low + + * New upstream release. + + -- Matt Corallo Sat, 15 Dec 2012 10:59:00 -0400 + +bitcoin (0.7.1-natty1) natty; urgency=low + + * New upstream release. + + -- Matt Corallo Wed, 24 Oct 2012 15:06:00 -0400 + +bitcoin (0.7.0-natty1) natty; urgency=low + + * New upstream release. + + -- Matt Corallo Mon, 17 Sep 2012 13:45:00 +0200 + bitcoin (0.6.3-natty1) natty; urgency=low * New upstream release. diff --git a/contrib/debian/control b/contrib/debian/control index c8266f6..dd167ef 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -33,8 +33,6 @@ Description: peer-to-peer network based digital currency - daemon transact directly with each other, with the help of a P2P network to check for double-spending. . - By default connects to an IRC network to discover other peers. - . Full transaction history is stored locally at each client. This requires 2+ GB of space, slowly growing. . @@ -51,8 +49,6 @@ Description: peer-to-peer network based digital currency - Qt GUI transact directly with each other, with the help of a P2P network to check for double-spending. . - By default connects to an IRC network to discover other peers. - . Full transaction history is stored locally at each client. This requires 2+ GB of space, slowly growing. . diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 71913c5..85ea75a 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -55,8 +55,7 @@ Comment: Icon Pack: Human-O2 Files: src/qt/res/icons/transaction*.png Copyright: md2k7 -License: You are free to do with these icons as you wish, including selling, - copying, modifying etc. +License: Expat Comment: Site: https://bitcointalk.org/index.php?topic=15276.0 Files: src/qt/res/icons/configure.png, src/qt/res/icons/quit.png, @@ -78,7 +77,7 @@ License: GPL-3+ Comment: Icon Pack: Kids Site: http://findicons.com/icon/17102/reload?id=17102 -Files: src/qt/res/images/splash2.jpg +Files: src/qt/res/images/splash.jpg License: PUB-DOM Copyright: Crobbo (forum) Comment: Site: https://bitcointalk.org/index.php?topic=32273.0 diff --git a/contrib/debian/examples/bitcoin.conf b/contrib/debian/examples/bitcoin.conf index e56c43c..496b1a7 100644 --- a/contrib/debian/examples/bitcoin.conf +++ b/contrib/debian/examples/bitcoin.conf @@ -11,16 +11,12 @@ # Use as many addnode= settings as you like to connect to specific peers #addnode=69.164.218.197 -#addnode=10.0.0.2:8333 +#addnode=10.0.0.2:47950 # ... or use as many connect= settings as you like to connect ONLY # to specific peers: #connect=69.164.218.197 -#connect=10.0.0.1:8333 - -# Do not use Internet Relay Chat (irc.lfnet.org #bitcoin channel) to -# find other peers. -#noirc=1 +#connect=10.0.0.1:47950 # Maximum number of inbound+outbound connections. #maxconnections= @@ -42,7 +38,7 @@ #rpcallowip=192.168.1.* # Listen for RPC connections on this TCP port: -rpcport=8332 +rpcport=47970 # You can use Bitcoin or bitcoind to send commands to Bitcoin/bitcoind # running on another host using this option: diff --git a/contrib/debian/manpages/bitcoin-qt.1 b/contrib/debian/manpages/bitcoin-qt.1 new file mode 100644 index 0000000..4abba13 --- /dev/null +++ b/contrib/debian/manpages/bitcoin-qt.1 @@ -0,0 +1,206 @@ +.TH BITCOIN-QT "1" "April 2013" "bitcoin-qt 1" +.SH NAME +bitcoin-qt \- peer-to-peer network based digital currency +.SH DESCRIPTION +.SS "Usage:" +.IP +bitcoin\-qt [command\-line options] +.SH OPTIONS +.TP +\-? +This help message +.TP +\fB\-conf=\fR +Specify configuration file (default: bitcoin.conf) +.TP +\fB\-pid=\fR +Specify pid file (default: bitcoind.pid) +.TP +\fB\-gen\fR +Generate coins +.TP +\fB\-gen\fR=\fI0\fR +Don't generate coins +.TP +\fB\-datadir=\fR +Specify data directory +.TP +\fB\-dbcache=\fR +Set database cache size in megabytes (default: 25) +.TP +\fB\-timeout=\fR +Specify connection timeout in milliseconds (default: 5000) +.TP +\fB\-proxy=\fR +Connect through socks proxy +.TP +\fB\-socks=\fR +Select the version of socks proxy to use (4\-5, default: 5) +.TP +\fB\-tor=\fR +Use proxy to reach tor hidden services (default: same as \fB\-proxy\fR) +.TP +\fB\-dns\fR +Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR +.TP +\fB\-port=\fR +Listen for connections on (default: 47950 or testnet: 17950) +.TP +\fB\-maxconnections=\fR +Maintain at most connections to peers (default: 125) +.TP +\fB\-addnode=\fR +Add a node to connect to and attempt to keep the connection open +.TP +\fB\-connect=\fR +Connect only to the specified node(s) +.TP +\fB\-seednode=\fR +Connect to a node to retrieve peer addresses, and disconnect +.TP +\fB\-externalip=\fR +Specify your own public address +.TP +\fB\-onlynet=\fR +Only connect to nodes in network (IPv4, IPv6 or Tor) +.TP +\fB\-discover\fR +Discover own IP address (default: 1 when listening and no \fB\-externalip\fR) +.TP +\fB\-checkpoints\fR +Only accept block chain matching built\-in checkpoints (default: 1) +.TP +\fB\-listen\fR +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) +.TP +\fB\-bind=\fR +Bind to given address and always listen on it. Use [host]:port notation for IPv6 +.TP +\fB\-dnsseed\fR +Find peers using DNS lookup (default: 1 unless \fB\-connect\fR) +.TP +\fB\-banscore=\fR +Threshold for disconnecting misbehaving peers (default: 100) +.TP +\fB\-bantime=\fR +Number of seconds to keep misbehaving peers from reconnecting (default: 86400) +.TP +\fB\-maxreceivebuffer=\fR +Maximum per\-connection receive buffer, *1000 bytes (default: 5000) +.TP +\fB\-maxsendbuffer=\fR +Maximum per\-connection send buffer, *1000 bytes (default: 1000) +.TP +\fB\-upnp\fR +Use UPnP to map the listening port (default: 1 when listening) +.TP +\fB\-paytxfee=\fR +Fee per KB to add to transactions you send +.TP +\fB\-server\fR +Accept command line and JSON\-RPC commands +.TP +\fB\-testnet\fR +Use the test network +.TP +\fB\-debug\fR +Output extra debugging information. Implies all other \fB\-debug\fR* options +.TP +\fB\-debugnet\fR +Output extra network debugging information +.TP +\fB\-logtimestamps\fR +Prepend debug output with timestamp +.TP +\fB\-shrinkdebugfile\fR +Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR) +.TP +\fB\-printtoconsole\fR +Send trace/debug info to console instead of debug.log file +.TP +\fB\-rpcuser=\fR +Username for JSON\-RPC connections +.TP +\fB\-rpcpassword=\fR +Password for JSON\-RPC connections +.TP +\fB\-rpcport=\fR +Listen for JSON\-RPC connections on (default: 47970 or testnet: 17970) +.TP +\fB\-rpcallowip=\fR +Allow JSON\-RPC connections from specified IP address +.TP +\fB\-rpcthreads=\fR +Set the number of threads to service RPC calls (default: 4) +.TP +\fB\-blocknotify=\fR +Execute command when the best block changes (%s in cmd is replaced by block hash) +.TP +\fB\-walletnotify=\fR +Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) +.TP +\fB\-alertnotify=\fR +Execute command when a relevant alert is received (%s in cmd is replaced by message) +.TP +\fB\-upgradewallet\fR +Upgrade wallet to latest format +.TP +\fB\-keypool=\fR +Set key pool size to (default: 100) +.TP +\fB\-rescan\fR +Rescan the block chain for missing wallet transactions +.TP +\fB\-salvagewallet\fR +Attempt to recover private keys from a corrupt wallet.dat +.TP +\fB\-checkblocks=\fR +How many blocks to check at startup (default: 288, 0 = all) +.TP +\fB\-checklevel=\fR +How thorough the block verification is (0\-4, default: 3) +.TP +\fB\-txindex\fR +Maintain a full transaction index (default: 0) +.TP +\fB\-loadblock=\fR +Imports blocks from external blk000??.dat file +.TP +\fB\-reindex\fR +Rebuild block chain index from current blk000??.dat files +.TP +\fB\-par=\fR +Set the number of script verification threads (1\-16, 0=auto, default: 0) +.SS "Block creation options:" +.TP +\fB\-blockminsize=\fR +Set minimum block size in bytes (default: 0) +.TP +\fB\-blockmaxsize=\fR +Set maximum block size in bytes (default: 250000) +.HP +\fB\-blockprioritysize=\fR Set maximum size of high\-priority/low\-fee transactions in bytes (default: 27000) +.PP +SSL options: (see the Bitcoin Wiki for SSL setup instructions) +.TP +\fB\-rpcssl\fR +Use OpenSSL (https) for JSON\-RPC connections +.TP +\fB\-rpcsslcertificatechainfile=\fR +Server certificate file (default: server.cert) +.TP +\fB\-rpcsslprivatekeyfile=\fR +Server private key (default: server.pem) +.TP +\fB\-rpcsslciphers=\fR +Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) +.SS "UI options:" +.TP +\fB\-lang=\fR +Set language, for example "de_DE" (default: system locale) +.TP +\fB\-min\fR +Start minimized +.TP +\fB\-splash\fR +Show splash screen on startup (default: 1) diff --git a/contrib/debian/manpages/bitcoin.conf.5 b/contrib/debian/manpages/bitcoin.conf.5 index 1243253..c5da3af 100644 --- a/contrib/debian/manpages/bitcoin.conf.5 +++ b/contrib/debian/manpages/bitcoin.conf.5 @@ -2,11 +2,11 @@ .SH NAME bitcoin.conf \- bitcoin configuration file .SH SYNOPSIS -All command-line options (except for '-datadir' and '-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. +All command-line options (except for '\-datadir' and '\-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. .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. +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 NETWORK-RELATED SETTINGS @@ -18,15 +18,12 @@ Enable or disable run on the test network instead of the real *bitcoin* network. \fBproxy=\fR\fI'127.0.0.1:9050'\fR Connect via a socks4 proxy. .TP -\fBaddnode=\fR\fI'10.0.0.2:8333'\fR +\fBaddnode=\fR\fI'10.0.0.2:47950'\fR Use as many *addnode=* settings as you like to connect to specific peers. .TP -\fBconnect=\fR\fI'10.0.0.1:8333'\fR +\fBconnect=\fR\fI'10.0.0.1:47950'\fR Use as many *connect=* settings as you like to connect ONLY to specific peers. .TP -\fBnoirc=\fR[\fI'1'\fR|\fI'0'\fR] -Use or Do not use Internet Relay Chat (irc.lfnet.org #bitcoin channel) to find other peers. -.TP \fRmaxconnections=\fR\fI'value'\fR Maximum number of inbound+outbound connections. .SH JSON-RPC OPTIONS @@ -46,16 +43,17 @@ How many seconds *bitcoin* will wait for a complete RPC HTTP request, after the \fBrpcallowip=\fR\fI'192.168.1.*'\fR By default, only RPC connections from localhost are allowed. Specify as many *rpcallowip=* settings as you like to allow connections from other hosts (and you may use * as a wildcard character). .TP -\fBrpcport=\fR\fI'8332'\fR +\fBrpcport=\fR\fI'47970'\fR Listen for RPC connections on this TCP port. .TP \fBrpcconnect=\fR\fI'127.0.0.1'\fR You can use *bitcoin* or *bitcoind(1)* to send commands to *bitcoin*/*bitcoind(1)* running on another host using this option. .TP \fBrpcssl=\fR\fI'1'\fR -Use Secure Sockets Layer (also known as TLS or HTTPS) to communicate with *bitcoin* '-server' or *bitcoind(1)*. Example of OpenSSL settings used when *rpcssl*='1': +Use Secure Sockets Layer (also known as TLS or HTTPS) to communicate with *bitcoin* '\-server' or *bitcoind(1)*. Example of OpenSSL settings used when *rpcssl*='1': .TP -\fBrpcsslciphers=\fR\fI'TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH'\fR +\fB\-rpcsslciphers=\fR +Acceptable ciphers (default: TLSv1+HIGH:\:!SSLv2:\:!aNULL:\:!eNULL:\:!AH:\:!3DES:\:@STRENGTH) .TP \fBrpcsslcertificatechainfile=\fR\fI'server.cert'\fR .TP diff --git a/contrib/debian/manpages/bitcoind.1 b/contrib/debian/manpages/bitcoind.1 index bf46a66..0c191b6 100644 --- a/contrib/debian/manpages/bitcoind.1 +++ b/contrib/debian/manpages/bitcoind.1 @@ -4,7 +4,7 @@ bitcoind \- peer-to-peer network based digital currency .SH SYNOPSIS bitcoin [options] [params] .TP -bitcoin [options] help - Get help for a command +bitcoin [options] help \- Get help for a command .SH DESCRIPTION This manual page documents the bitcoind program. Bitcoin is a peer-to-peer digital currency. Peer-to-peer (P2P) means that there is no central authority to issue new money or keep track of transactions. Instead, these tasks are managed collectively by the nodes of the network. Advantages: @@ -75,7 +75,7 @@ Server certificate file (default: server.cert) Server private key (default: server.pem) .TP \fB\-rpcsslciphers=\fR -Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) +Acceptable ciphers (default: TLSv1+HIGH:\:!SSLv2:\:!aNULL:\:!eNULL:\:!AH:\:!3DES:\:@STRENGTH) .TP \-? This help message @@ -115,7 +115,7 @@ Returns the proof-of-work difficulty as a multiple of the minimum difficulty. Returns boolean true if server is trying to generate bitcoins, false otherwise. .TP \fBsetgenerate 'generate' ['genproclimit']\fR -Generation is limited to ['genproclimit'] processors, -1 is unlimited. +Generation is limited to ['genproclimit'] processors, \-1 is unlimited. .TP \fBgethashespersec\fR Returns a recent hashes per second performance measurement while generating. @@ -166,7 +166,7 @@ List accounts and their current balances. "confirmations" : number of confirmations of the most recent transaction included. .TP \fBlisttransactions 'account' ['count=10']\fR -Returns a list of the last ['count'] transactions for 'account' - for all accounts if 'account' is not specified or is "*". Each entry in the list may contain: +Returns a list of the last ['count'] transactions for 'account' \- for all accounts if 'account' is not specified or is "*". Each entry in the list may contain: "category" : will be generate, send, receive, or move. "amount" : amount of transaction. diff --git a/contrib/gitian-descriptors/README b/contrib/gitian-descriptors/README index a2d902e..46c7668 100644 --- a/contrib/gitian-descriptors/README +++ b/contrib/gitian-descriptors/README @@ -1,31 +1,86 @@ -Gavin's notes on getting gitian builds up and running: +Gavin's notes on getting gitian builds up and running using KVM: + +These instructions distilled from: + https://help.ubuntu.com/community/KVM/Installation +... see there for complete details. You need the right hardware: you need a 64-bit-capable CPU with hardware virtualization support (Intel VT-x or AMD-V). Not all modern CPUs support hardware virtualization. You probably need to enable hardware virtualization in your machine's BIOS. You need to be running a recent version of 64-bit-Ubuntu, and you need to install several prerequisites: - sudo apt-get install apache2 git apt-cacher-ng python-vm-builder qemu-kvm + sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm Sanity checks: sudo service apt-cacher-ng status # Should return apt-cacher-ng is running ls -l /dev/kvm # Should show a /dev/kvm device + Once you've got the right hardware and software: git clone git://github.com/bitcoin/bitcoin.git git clone git://github.com/devrandom/gitian-builder.git mkdir gitian-builder/inputs - wget 'http://miniupnp.tuxfamily.org/files/download.php?file=miniupnpc-1.6.tar.gz' -O gitian-builder/inputs/miniupnpc-1.6.tar.gz + cd gitian-builder/inputs + # Inputs for Linux and Win32: + wget -O miniupnpc-1.6.tar.gz 'http://miniupnp.tuxfamily.org/files/download.php?file=miniupnpc-1.6.tar.gz' + wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2' + # Inputs for Win32: (Linux has packages for these) + wget 'https://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2' + wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz' + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' + wget 'https://downloads.sourceforge.net/project/libpng/zlib/1.2.6/zlib-1.2.6.tar.gz' + wget 'https://downloads.sourceforge.net/project/libpng/libpng15/older-releases/1.5.9/libpng-1.5.9.tar.gz' + wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz' + cd ../.. cd gitian-builder bin/make-base-vm --arch i386 bin/make-base-vm --arch amd64 cd .. - # To build + # Build Linux release: cd bitcoin git pull cd ../gitian-builder git pull - ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian.yml + ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian-descriptors/gitian.yml + + # Build Win32 dependencies: (only needs to be done once, or when dependency versions change) + ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian-descriptors/boost-win32.yml + ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian-descriptors/deps-win32.yml + ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian-descriptors/qt-win32.yml + + # Build Win32 release: + ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + +--------------------- + +gitian-builder now also supports building using LXC. See + https://help.ubuntu.com/12.04/serverguide/lxc.html +... for how to get LXC up and running under Ubuntu. + +If your main machine is a 64-bit Mac or PC with a few gigabytes of memory +and at least 10 gigabytes of free disk space, you can gitian-build using +LXC running inside a virtual machine. + +Here's a description of Gavin's setup on OSX 10.6: + +1. Download and install VirtualBox from https://www.virtualbox.org/ + +2. Download the 64-bit Ubuntu Desktop 12.04 LTS .iso CD image from + http://www.ubuntu.com/ + +3. Run VirtualBox and create a new virtual machine, using the + Ubuntu .iso (see the VirtualBox documentation for details). + Create it with at least 2 gigabytes of memory and a disk + that is at least 20 gigabytes big. + +4. Inside the running Ubuntu desktop, install: + sudo apt-get install debootstrap lxc ruby apache2 git apt-cacher-ng python-vm-builder + +5. Still inside Ubuntu, tell gitian-builder to use LXC, then follow the "Once you've got the right + hardware and software" instructions above: + export USE_LXC=1 + git clone git://github.com/bitcoin/bitcoin.git + ... etc diff --git a/contrib/gitian-descriptors/boost-win32.yml b/contrib/gitian-descriptors/boost-win32.yml index c4a9f33..b14cd1f 100644 --- a/contrib/gitian-descriptors/boost-win32.yml +++ b/contrib/gitian-descriptors/boost-win32.yml @@ -1,38 +1,66 @@ --- name: "boost" suites: -- "lucid" +- "precise" architectures: -- "i386" -packages: -- "mingw32" +- "amd64" +packages: +- "mingw-w64" +- "g++-mingw-w64" - "faketime" - "zip" reference_datetime: "2011-01-30 00:00:00" remotes: [] files: -- "boost_1_49_0.tar.bz2" +- "boost_1_55_0.tar.bz2" +- "boost-mingw-gas-cross-compile-2013-03-03.patch" script: | - TMPDIR="$HOME/tmpdir" - mkdir -p $TMPDIR/bin/$GBUILD_BITS $TMPDIR/include - tar xjf boost_1_49_0.tar.bz2 - cd boost_1_49_0 - echo "using gcc : 4.4 : i586-mingw32msvc-g++ + # Defines + INSTALLPREFIX="$OUTDIR/staging/boost" + HOST=i686-w64-mingw32 + # Input Integrity Check + echo "fff00023dd79486d444c8e29922f4072e1d451fc5a4d2b6075852ead7f2b7b52 boost_1_55_0.tar.bz2" | shasum -c + echo "d2b7f6a1d7051faef3c9cf41a92fa3671d905ef1e1da920d07651a43299f6268 boost-mingw-gas-cross-compile-2013-03-03.patch" | shasum -c + + mkdir -p "$INSTALLPREFIX" + tar xjf boost_1_55_0.tar.bz2 + cd boost_1_55_0 + GCCVERSION=$($HOST-g++ -E -dM $(mktemp --suffix=.h) | grep __VERSION__ | cut -d ' ' -f 3 | cut -d '"' -f 2) + echo "using gcc : $GCCVERSION : $HOST-g++ : - i586-mingw32msvc-windres - i586-mingw32msvc-ar + $HOST-windres + $HOST-ar -frandom-seed=boost1 + $HOST-ranlib ;" > user-config.jam ./bootstrap.sh --without-icu - ./bjam toolset=gcc target-os=windows threadapi=win32 threading=multi variant=release link=static --user-config=user-config.jam --without-mpi --without-python -sNO_BZIP2=1 -sNO_ZLIB=1 --layout=tagged --build-type=complete $MAKEOPTS stage - for lib in chrono date_time exception filesystem graph iostreams math_c99f math_c99l math_c99 math_tr1f math_tr1l math_tr1 prg_exec_monitor program_options random regex serialization signals system test_exec_monitor thread_win32 unit_test_framework wave wserialization; do - mkdir $lib - (cd $lib ; ar xf ../stage/lib/libboost_${lib}-mt-s.a) - mv $lib $TMPDIR/bin/$GBUILD_BITS - done - cp -a boost $TMPDIR/include - cd $TMPDIR + + # Workaround: Upstream boost dev refuses to include patch that would allow Free Software cross-compile toolchain to work + # This patch was authored by the Fedora package developer and ships in Fedora's mingw32-boost. + # Please obtain the exact patch that matches the above sha256sum from one of the following mirrors. + # + # Read History: https://svn.boost.org/trac/boost/ticket/7262 + # History Mirror: http://rose.makesad.us/~paulproteus/mirrors/7262%20Boost.Context%20fails%20to%20build%20using%20MinGW.html + # + # Patch: https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch + # Patch Mirror: http://wtogami.fedorapeople.org/boost-mingw-gas-cross-compile-2013-03-03.patch + # Patch Mirror: http://mindstalk.net/host/boost-mingw-gas-cross-compile-2013-03-03.patch + # Patch Mirror: http://rose.makesad.us/~paulproteus/mirrors/boost-mingw-gas-cross-compile-2013-03-03.patch + patch -p0 < ../boost-mingw-gas-cross-compile-2013-03-03.patch + + # Bug Workaround: boost-1.54.0 broke the ability to disable zlib, still broken in 1.55 + # https://svn.boost.org/trac/boost/ticket/9156 + sed -i 's^\[ ac.check-library /zlib//zlib : /zlib//zlib^^' libs/iostreams/build/Jamfile.v2 + sed -i 's^zlib.cpp gzip.cpp \]^^' libs/iostreams/build/Jamfile.v2 + + # http://statmt.org/~s0565741/software/boost_1_52_0/libs/context/doc/html/context/requirements.html + # Note: Might need these options in the future for 64bit builds. + # "Please note that address-model=64 must be given to bjam command line on 64bit Windows for 64bit build; otherwise 32bit code will be generated." + # "For cross-compiling the lib you must specify certain additional properties at bjam command line: target-os, abi, binary-format, architecture and address-model." + ./bjam toolset=gcc binary-format=pe target-os=windows threadapi=win32 threading=multi variant=release link=static --user-config=user-config.jam --without-mpi --without-python -sNO_BZIP2=1 -sNO_ZLIB=1 --layout=tagged --build-type=complete --prefix="$INSTALLPREFIX" $MAKEOPTS install + + cd "$INSTALLPREFIX" export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 export FAKETIME=$REFERENCE_DATETIME - zip -r boost-win32-1.49.0-gitian2.zip * - cp boost-win32-1.49.0-gitian2.zip $OUTDIR + zip -r boost-win32-1.55.0-gitian-r6.zip * + cp boost-win32-1.55.0-gitian-r6.zip $OUTDIR diff --git a/contrib/gitian-descriptors/deps-win32.yml b/contrib/gitian-descriptors/deps-win32.yml index 941c9f2..7ad00fc 100644 --- a/contrib/gitian-descriptors/deps-win32.yml +++ b/contrib/gitian-descriptors/deps-win32.yml @@ -1,72 +1,93 @@ --- -name: "casinocoin-deps" +name: "bitcoin-deps" suites: -- "lucid" +- "precise" architectures: -- "i386" -packages: -- "mingw32" +- "amd64" +packages: +- "mingw-w64" +- "g++-mingw-w64" - "git-core" - "zip" - "faketime" -- "wine" - "psmisc" reference_datetime: "2011-01-30 00:00:00" remotes: [] files: -- "openssl-1.0.1b.tar.gz" +- "openssl-1.0.1c.tar.gz" - "db-4.8.30.NC.tar.gz" - "miniupnpc-1.6.tar.gz" -- "zlib-1.2.7.tar.gz" -- "libpng-1.5.12.tar.gz" +- "zlib-1.2.6.tar.gz" +- "libpng-1.5.9.tar.gz" - "qrencode-3.2.0.tar.bz2" script: | # export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 export FAKETIME=$REFERENCE_DATETIME export TZ=UTC + export INSTALLPREFIX=$OUTDIR/staging/deps + export HOST=i686-w64-mingw32 # - tar xzf openssl-1.0.1b.tar.gz - cd openssl-1.0.1b - ./Configure --cross-compile-prefix=i586-mingw32msvc- mingw + mkdir -p $INSTALLPREFIX + + tar xzf openssl-1.0.1c.tar.gz + cd openssl-1.0.1c + ./Configure --cross-compile-prefix=$HOST- mingw --openssldir=$INSTALLPREFIX make + make install_sw cd .. # tar xzf db-4.8.30.NC.tar.gz cd db-4.8.30.NC/build_unix - ../dist/configure --enable-mingw --enable-cxx --host=i586-mingw32msvc CFLAGS="-I/usr/i586-mingw32msvc/include" - make $MAKEOPTS + ../dist/configure --prefix=$INSTALLPREFIX --enable-mingw --enable-cxx --host=$HOST --disable-shared + make $MAKEOPTS library_build + make install_lib install_include cd ../.. # tar xzf miniupnpc-1.6.tar.gz cd miniupnpc-1.6 - sed 's/dllwrap -k --driver-name gcc/$(DLLWRAP) -k --driver-name $(CC)/' -i Makefile.mingw - sed 's|wingenminiupnpcstrings $< $@|./wingenminiupnpcstrings $< $@|' -i Makefile.mingw - make -f Makefile.mingw DLLWRAP=i586-mingw32msvc-dllwrap CC=i586-mingw32msvc-gcc AR=i586-mingw32msvc-ar - cd .. - mv miniupnpc-1.6 miniupnpc - # - tar xzf zlib-1.2.7.tar.gz - cd zlib-1.2.7 - make -f win32/Makefile.gcc PREFIX=i586-mingw32msvc- $MAKEOPTS + echo " + --- miniupnpc-1.6/Makefile.mingw.orig 2013-09-29 18:52:51.014087958 -1000 + +++ miniupnpc-1.6/Makefile.mingw 2013-09-29 19:09:29.663318691 -1000 + @@ -67,8 +67,8 @@ + + wingenminiupnpcstrings.o: wingenminiupnpcstrings.c + + -miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings + - wingenminiupnpcstrings \$< \$@ + +miniupnpcstrings.h: miniupnpcstrings.h.in + + sed -e 's|OS/version|MSWindows/5.1.2600|' -e 's|MINIUPNPC_VERSION_STRING \"version\"|MINIUPNPC_VERSION_STRING \"VERSIONHERE\"|' \$< > \$@ + + minixml.o: minixml.c minixml.h miniupnpcstrings.h + + " | sed "s/VERSIONHERE/$(cat VERSION)/" | patch -p1 + mkdir -p dll + make -f Makefile.mingw CC=$HOST-gcc AR=$HOST-ar libminiupnpc.a + install -d $INSTALLPREFIX/include/miniupnpc + install *.h $INSTALLPREFIX/include/miniupnpc + install libminiupnpc.a $INSTALLPREFIX/lib cd .. # - tar xzf libpng-1.5.12.tar.gz - cd libpng-1.5.12 - ./configure -disable-shared CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld LDFLAGS="-L../zlib-1.2.7/" CFLAGS="-I../zlib-1.2.7/" + tar xzf zlib-1.2.6.tar.gz + cd zlib-1.2.6 + CROSS_PREFIX=$HOST- ./configure --prefix=$INSTALLPREFIX --static + make + make install + cd .. + # + tar xzf libpng-1.5.9.tar.gz + cd libpng-1.5.9 + CFLAGS="-I$INSTALLPREFIX/include" LDFLAGS="-L$INSTALLPREFIX/lib" ./configure --disable-shared --prefix=$INSTALLPREFIX --host=$HOST make $MAKEOPTS + make install cd .. # tar xjf qrencode-3.2.0.tar.bz2 cd qrencode-3.2.0 - ./configure CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld png_LIBS="../libpng-1.5.12/.libs/libpng15.a ../zlib-1.2.7/libz.a" png_CFLAGS="-I../libpng-1.5.12" - make $MAKEOPTS + png_CFLAGS="-I$INSTALLPREFIX/include" png_LIBS="-L$INSTALLPREFIX/lib -lpng" ./configure --prefix=$INSTALLPREFIX --host=$HOST + make + make install cd .. # - zip -r $OUTDIR/casinocoin-deps-0.0.4.zip \ - $(ls qrencode-*/{qrencode.h,.libs/libqrencode.{,l}a} | sort) \ - $(ls db-*/build_unix/{libdb_cxx.a,db.h,db_cxx.h,libdb.a,.libs/libdb_cxx-?.?.a} | sort) \ - $(find openssl-* -name '*.a' -o -name '*.h' | sort) \ - $(find miniupnpc -name '*.h' -o -name 'libminiupnpc.a' | sort) - # Kill wine processes as gitian won't figure out we are done otherwise - killall wineserver services.exe explorer.exe winedevice.exe + cd $INSTALLPREFIX + zip -r $OUTDIR/bitcoin-deps-win32-gitian-r9.zip include lib diff --git a/contrib/gitian-descriptors/gitian-win32.yml b/contrib/gitian-descriptors/gitian-win32.yml index 62e44f2..42e92db 100644 --- a/contrib/gitian-descriptors/gitian-win32.yml +++ b/contrib/gitian-descriptors/gitian-win32.yml @@ -1,11 +1,12 @@ --- name: "casinocoin" suites: -- "lucid" +- "precise" architectures: -- "i386" -packages: -- "mingw32" +- "amd64" +packages: +- "mingw-w64" +- "g++-mingw-w64" - "git-core" - "unzip" - "nsis" @@ -15,53 +16,42 @@ remotes: - "url": "https://github.com/casinocoin-project/casinocoin.git" "dir": "casinocoin" files: -- "qt-win32-4.7.4-gitian.zip" -- "boost-win32-1.49.0-gitian2.zip" -- "casinocoin-deps-0.0.4.zip" +- "qt-win32-4.8.3-gitian-r4.zip" +- "boost-win32-1.55.0-gitian-r6.zip" +- "bitcoin-deps-win32-gitian-r9.zip" script: | # - mkdir $HOME/qt - cd $HOME/qt - unzip ../build/qt-win32-4.7.4-gitian.zip + STAGING=$HOME/staging + HOST=i686-w64-mingw32 + # + mkdir -p $STAGING + cd $STAGING + unzip ../build/qt-win32-4.8.3-gitian-r4.zip + unzip ../build/boost-win32-1.55.0-gitian-r6.zip + unzip ../build/bitcoin-deps-win32-gitian-r9.zip cd $HOME/build/ - export PATH=$PATH:$HOME/qt/bin/ - # - mkdir boost_1_49_0 - cd boost_1_49_0 - mkdir -p stage/lib - unzip ../boost-win32-1.49.0-gitian2.zip - cd bin/$GBUILD_BITS - for lib in *; do - i586-mingw32msvc-ar rc ../../stage/lib/libboost_${lib}-mt-s.a $lib/*.o - i586-mingw32msvc-ranlib ../../stage/lib/libboost_${lib}-mt-s.a - done - cd ../.. - mv include/boost . - cd .. - # - unzip casinocoin-deps-0.0.4.zip - # - find -type f | xargs touch --date="$REFERENCE_DATETIME" # cd casinocoin + export PATH=$STAGING/host/bin:$PATH mkdir -p $OUTDIR/src git archive HEAD | tar -x -C $OUTDIR/src cp $OUTDIR/src/doc/README_windows.txt $OUTDIR/readme.txt - cp $OUTDIR/src/COPYING $OUTDIR/license.txt + cp $OUTDIR/src/COPYING $OUTDIR/COPYING.txt export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 export FAKETIME=$REFERENCE_DATETIME export TZ=UTC - $HOME/qt/src/bin/qmake -spec unsupported/win32-g++-cross MINIUPNPC_LIB_PATH=$HOME/build/miniupnpc MINIUPNPC_INCLUDE_PATH=$HOME/build/ BDB_LIB_PATH=$HOME/build/db-4.8.30.NC/build_unix BDB_INCLUDE_PATH=$HOME/build/db-4.8.30.NC/build_unix BOOST_LIB_PATH=$HOME/build/boost_1_49_0/stage/lib BOOST_INCLUDE_PATH=$HOME/build/boost_1_49_0 BOOST_LIB_SUFFIX=-mt-s BOOST_THREAD_LIB_SUFFIX=_win32-mt-s OPENSSL_LIB_PATH=$HOME/build/openssl-1.0.1b OPENSSL_INCLUDE_PATH=$HOME/build/openssl-1.0.1b/include QRENCODE_LIB_PATH=$HOME/build/qrencode-3.2.0/.libs QRENCODE_INCLUDE_PATH=$HOME/build/qrencode-3.2.0 USE_QRCODE=1 INCLUDEPATH=$HOME/build DEFINES=BOOST_THREAD_USE_LIB BITCOIN_NEED_QT_PLUGINS=1 QMAKE_LRELEASE=lrelease QMAKE_CXXFLAGS=-frandom-seed=bitcoin QMAKE_LFLAGS=-frandom-seed=bitcoin USE_BUILD_INFO=1 + ln -s $STAGING $HOME/qt + $HOME/staging/host/bin/qmake -spec unsupported/win32-g++-cross MINIUPNPC_LIB_PATH=$STAGING MINIUPNPC_INCLUDE_PATH=$STAGING BDB_LIB_PATH=$STAGING BDB_INCLUDE_PATH=$STAGING BOOST_LIB_PATH=$STAGING BOOST_INCLUDE_PATH=$STAGING BOOST_LIB_SUFFIX=-mt-s BOOST_THREAD_LIB_SUFFIX=_win32-mt-s OPENSSL_LIB_PATH=$STAGING OPENSSL_INCLUDE_PATH=$STAGING QRENCODE_LIB_PATH=$STAGING QRENCODE_INCLUDE_PATH=$STAGING USE_QRCODE=1 INCLUDEPATH=$STAGING DEFINES=BOOST_THREAD_USE_LIB BITCOIN_NEED_QT_PLUGINS=1 QMAKE_LRELEASE=lrelease QMAKE_CXXFLAGS=-frandom-seed=casinocoin USE_BUILD_INFO=1 USE_SSE2=1 make $MAKEOPTS - i586-mingw32msvc-strip release/casinocoin-qt.exe + $HOST-strip release/casinocoin-qt.exe cp release/casinocoin-qt.exe $OUTDIR/ # cd src export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 export FAKETIME=$REFERENCE_DATETIME export TZ=UTC - make -f makefile.linux-mingw $MAKEOPTS DEPSDIR=$HOME/build casinocoind.exe USE_UPNP=0 DEBUGFLAGS="-frandom-seed=casinocoin" - i586-mingw32msvc-strip casinocoind.exe + make -f makefile.linux-mingw $MAKEOPTS DEPSDIR=$STAGING casinocoind.exe USE_UPNP=0 DEBUGFLAGS="-frandom-seed=casinocoin" USE_SSE2=1 + $HOST-strip casinocoind.exe mkdir $OUTDIR/daemon cp casinocoind.exe $OUTDIR/daemon cd .. diff --git a/contrib/gitian-descriptors/gitian.yml b/contrib/gitian-descriptors/gitian.yml index dd8e700..2ff8b5c 100644 --- a/contrib/gitian-descriptors/gitian.yml +++ b/contrib/gitian-descriptors/gitian.yml @@ -43,13 +43,13 @@ script: | cd casinocoin mkdir -p $OUTDIR/src git archive HEAD | tar -x -C $OUTDIR/src - cp $OUTDIR/src/doc/README $OUTDIR + cp $OUTDIR/src/doc/README.md $OUTDIR cp $OUTDIR/src/COPYING $OUTDIR cd src - make -f makefile.unix STATIC=1 OPENSSL_INCLUDE_PATH="$INSTDIR/include" OPENSSL_LIB_PATH="$INSTDIR/lib" $MAKEOPTS casinocoind USE_UPNP=0 DEBUGFLAGS= + make -f makefile.unix STATIC=1 OPENSSL_INCLUDE_PATH="$INSTDIR/include" OPENSSL_LIB_PATH="$INSTDIR/lib" $MAKEOPTS casinocoind USE_UPNP=0 DEBUGFLAGS= USE_SSE2=1 mkdir -p $OUTDIR/bin/$GBUILD_BITS install -s casinocoind $OUTDIR/bin/$GBUILD_BITS cd .. - qmake INCLUDEPATH="$INSTDIR/include" LIBS="-L$INSTDIR/lib" RELEASE=1 USE_QRCODE=1 + qmake INCLUDEPATH="$INSTDIR/include" LIBS="-L$INSTDIR/lib" RELEASE=1 USE_QRCODE=1 USE_SSE2=1 make $MAKEOPTS - install -s casinocoin-qt $OUTDIR/bin/$GBUILD_BITS + install casinocoin-qt $OUTDIR/bin/$GBUILD_BITS diff --git a/contrib/gitian-descriptors/qt-win32.yml b/contrib/gitian-descriptors/qt-win32.yml index 6eb76b2..0615340 100644 --- a/contrib/gitian-descriptors/qt-win32.yml +++ b/contrib/gitian-descriptors/qt-win32.yml @@ -1,54 +1,62 @@ --- name: "qt" suites: -- "lucid" +- "precise" architectures: -- "i386" +- "amd64" packages: -- "mingw32" +- "mingw-w64" +- "g++-mingw-w64" - "zip" +- "unzip" - "faketime" reference_datetime: "2011-01-30 00:00:00" remotes: [] files: -- "qt-everywhere-opensource-src-4.7.4.tar.gz" +- "qt-everywhere-opensource-src-4.8.3.tar.gz" +- "bitcoin-deps-win32-gitian-r9.zip" script: | - INSTDIR="$HOME/qt/" - mkdir $INSTDIR - SRCDIR="$INSTDIR/src/" - mkdir $SRCDIR # - tar xzf qt-everywhere-opensource-src-4.7.4.tar.gz - cd qt-everywhere-opensource-src-4.7.4 + HOST=i686-w64-mingw32 + INSTDIR="$HOME/qt/" + # + mkdir $INSTDIR + mkdir -p $INSTDIR/host/bin + # + # Need mingw-compiled openssl from bitcoin-deps: + unzip bitcoin-deps-win32-gitian-r9.zip + DEPSDIR=`pwd` + # + tar xzf qt-everywhere-opensource-src-4.8.3.tar.gz + cd qt-everywhere-opensource-src-4.8.3 sed 's/$TODAY/2011-01-30/' -i configure - sed 's/i686-pc-mingw32-/i586-mingw32msvc-/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf - sed --posix 's|QMAKE_CFLAGS\t\t= -pipe|QMAKE_CFLAGS\t\t= -pipe -isystem /usr/i586-mingw32msvc/include/ -frandom-seed=qtbuild|' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed "s/i686-pc-mingw32-/$HOST-/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix "s|QMAKE_CFLAGS\t\t= -pipe|QMAKE_CFLAGS\t\t= -pipe -isystem /usr/$HOST/include/ -frandom-seed=qtbuild|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf sed 's/QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads/QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf sed 's/QMAKE_LFLAGS_EXCEPTIONS_ON = -mthreads/QMAKE_LFLAGS_EXCEPTIONS_ON = -lmingwthrd/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf - sed --posix 's/QMAKE_MOC\t\t= i586-mingw32msvc-moc/QMAKE_MOC\t\t= moc/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf - sed --posix 's/QMAKE_RCC\t\t= i586-mingw32msvc-rcc/QMAKE_RCC\t\t= rcc/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf - sed --posix 's/QMAKE_UIC\t\t= i586-mingw32msvc-uic/QMAKE_UIC\t\t= uic/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix "s/QMAKE_MOC\t\t= $HOST-moc/QMAKE_MOC\t\t= moc/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix "s/QMAKE_RCC\t\t= $HOST-rcc/QMAKE_RCC\t\t= rcc/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix "s/QMAKE_UIC\t\t= $HOST-uic/QMAKE_UIC\t\t= uic/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf # ar adds timestamps to every object file included in the static library # providing -D as ar argument is supposed to solve it, but doesn't work as qmake strips off the arguments and adds -M to pass a script... # which somehow cannot be combined with other flags. # use faketime only for ar, as it confuses make/qmake into hanging sometimes - sed --posix "s|QMAKE_LIB\t\t= i586-mingw32msvc-ar -ru|QMAKE_LIB\t\t= $HOME/ar -Dr|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix "s|QMAKE_LIB\t\t= $HOST-ar -ru|QMAKE_LIB\t\t= $HOME/ar -Dr|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf echo '#!/bin/bash' > $HOME/ar echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> $HOME/ar - echo 'i586-mingw32msvc-ar "$@"' >> $HOME/ar + echo "$HOST-ar \"\$@\"" >> $HOME/ar chmod +x $HOME/ar #export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 export FAKETIME=$REFERENCE_DATETIME export TZ=UTC - ./configure -prefix $INSTDIR -confirm-license -release -opensource -static -no-qt3support -xplatform unsupported/win32-g++-cross -no-multimedia -no-audio-backend -no-phonon -no-phonon-backend -no-declarative -no-script -no-scripttools -no-javascript-jit -no-webkit -no-svg -no-xmlpatterns -no-sql-sqlite -no-nis -no-cups -no-iconv -no-dbus -no-gif -no-libtiff -opengl no -nomake examples -nomake demos -nomake docs + # Compile static libraries, and use statically linked openssl (-openssl-linked): + OPENSSL_LIBS="-L$DEPSDIR/lib -lssl -lcrypto -lgdi32" ./configure -prefix $INSTDIR -bindir $INSTDIR/host/bin -I $DEPSDIR/include -confirm-license -release -opensource -static -no-qt3support -xplatform unsupported/win32-g++-cross -no-multimedia -no-audio-backend -no-phonon -no-phonon-backend -no-declarative -no-script -no-scripttools -no-javascript-jit -no-webkit -no-svg -no-xmlpatterns -no-sql-sqlite -no-nis -no-cups -no-iconv -no-dbus -no-gif -no-libtiff -no-opengl -nomake examples -nomake demos -nomake docs -no-feature-style-plastique -no-feature-style-cleanlooks -no-feature-style-motif -no-feature-style-cde -no-feature-style-windowsce -no-feature-style-windowsmobile -no-feature-style-s60 -openssl-linked find . -name *.prl | xargs -l sed 's|/\.||' -i find . -name *.prl | xargs -l sed 's|/$||' -i make $MAKEOPTS install - cp -a bin $SRCDIR/ cd $INSTDIR find . -name *.prl | xargs -l sed 's|/$||' -i - #sed 's|QMAKE_PRL_LIBS.*|QMAKE_PRL_LIBS = -lQtDeclarative -lQtScript -lQtSvg -lQtSql -lQtXmlPatterns -lQtGui -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lmsimg32 -lQtNetwork -lQtCore -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32|' -i imports/Qt/labs/particles/qmlparticlesplugin.prl # as zip stores file timestamps, use faketime to intercept stat calls to set dates for all files to reference date export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 - zip -r $OUTDIR/qt-win32-4.7.4-gitian.zip * + zip -r $OUTDIR/qt-win32-4.8.3-gitian-r4.zip * diff --git a/contrib/gitian-downloader/aspect-key.pgp b/contrib/gitian-downloader/aspect-key.pgp new file mode 100644 index 0000000..3fe3902 --- /dev/null +++ b/contrib/gitian-downloader/aspect-key.pgp @@ -0,0 +1,20 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +mQENBFHHt8wBCADfLkCS9624TrJ4pbFf5Cg88p0Sp7qofcPGjPa6K1Gs9cLfPHLu +EX17YvS9zxdmdlogVDGQ3d82O2OrjDCr26yioZteHsK1oPdzgwQJ5tAGxlv75UiW +BvhaDKXVfX+rdb+wnK3YMhynNQbG6pxQ0Q1Qujh6Xw0b1wbvg2FNEwpfHmL1ZoYd +ba0w6eRmREBMrk50lp8pmDxWjc7+7SdKPxqWsPpWOJTaMBVQNSaVr7ePoCOKwFNI +7CQiqMlGJUG1Zb7CnEkbiwNSwEi0VQkz8Ir8gBFzCTEgt2K1EGO8yo0Mq0hNTRdW +bC14pamlbu/+nx+LAefSJ9sMx7n/uzTjI1uTABEBAAG0LUFudG9uIFllbWVseWFu +b3YgPGFudG9uLnllbWVseWFub3ZAZ21haWwuY29tPokBOQQTAQIAIwUCUce3zAIb +DwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEKFZZWb4e+YxUwIIAM7DoCnv +lJXX5+z9My0RBIpd99if1udXBVtVxPgaF7lDDIaKY2cBktyXBp/R/G8arYRc9zIK +e+0bY+POpTrfMoTioqbiwoxPwhkXu39KwvPfSWY1UBQHTcMpFibMuFjRu6YrAEZ2 +ZH+CrLcmn6rB66uVm3OPE55sKdAL9C+TGIKU/GIRgQzI3S9/DT8E/F4Oifx/V9sh +V2flIXU2QBH4ZOP0G+OTp6QXZRD9TBfmrYRMU+yL5sYMalCjwz79ZZua50CQI5hN +5pEBvHxZ4GziWc5V40GSv1RnM/mGgrdmBlzej34OLjfEac2PCrZy8+FnQf04Lhvn +cRQpj+5V0a6RIfKIRgQQEQIABgUCUciczAAKCRBr3f6OVKKs8dqgAJ94zRvs99HM +pItL1r8v8vS5lXZrHgCfXy5V7AFtL8XvZlPC0uQqdyWKzHo= +=Bp2a +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/coblee-key.pgp b/contrib/gitian-downloader/coblee-key.pgp new file mode 100644 index 0000000..28497f5 --- /dev/null +++ b/contrib/gitian-downloader/coblee-key.pgp @@ -0,0 +1,75 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +mQINBE3zxrgBEAClsDj56PD9OheUjteWspOstSGxARKo05jeyK3wSM+dT7GIysxE +/0vyI7JS4GdYtFFIGbaPQRPgE+fs7BuSjQ5THHpOzna0lpxzE9lEmR1n2IntUpSL +7u2818Bu8HI5Tjjpw5VbCWjnbPfi2CfIoOgHUngRHy0cDBE86Ty/OmI7+2CwV0Ns ++Neo4NDJrMDmlOHr96+HZst33JKyeVJ+u8GzT0m3ilupGi/8UDDm0IDe61ZxAFqt +9NQyIi76rp8rD3yP/yH2PimmSjnFNiIhTAG6dEz97XN3pvzEkgBbPtd2c857SNb1 +zBGrORWBeIDbvHKGVfMPL6mt0MRTkGDlI3kf0dNooxNHZrtJNWRe3KeZpSo2fJbl +vYojpSqfZmGch+IJbC2KAqowfIzBuEVnyifoFQgS7gi7jBUHVYLamdUSY7cHRgCW +Qn/xj9liagk8QKS5L13q8rPDi466M84m/hp6HYMuSA9mhqDdp/JHA03lxHYOMSkf +QM5sZMeUGF9sEi/xaexV/KC9tzqhtmHHjn7GS5bwj/FrESFpCPaZAWCXzIuacmJ+ +lYAxf4uiBcC0qe4mU9AffmhYnNj4CCtW9CzpMP+gI/s0rdvgWuRgaE1LBTzdYFU2 +aVi61d8QY4PLiAsaMxm8gS/fwTnMSktLYhI4erOFa95+MVn18fVtxavgpQARAQAB +tCJDaGFybGVzIExlZSA8Y2hvY29ib0BhbHVtLm1pdC5lZHU+iQI4BBMBAgAiBQJN +88a4AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCCisH5TvJgU4KLD/4m +gbHmYlLqckM/wBg++pyf0ccnJqT05KiBD5NA0tNyGbcy6Ea+ppACsoFbr6zsSkhF +2HvKms2bZQrkZh7eCd8BxsQfJ1IiW1cZBa9v395ce0Xb7yyqHd1OhXokyhEAVgFo +lI1UP2eerkc/FGUGE5k3XPmMlpv1K54GGMozJNc7pScBR48e/cNQo0eizEKzZJH1 +d1fqrBVDyXMOEtkJyuPemCJgMmQ0heODCX1HxmoyuSmqtLSkjJOziCNGy1bbXpdp +G/imbRVQNVJCURDsztu17HHBMhJeN/xkGn830s3Eb6lQFkSMMtgwNqHbZfGflOSH +bfxvbFsQeqotlwED+Rzbsb+Xoua6I0SANPQVhf7gtlL7cWDOGTMsbbhhpSOI36/F +Qs51vItjBrWD+uYB8H5Cv6vkUvxVvn/70pD7pwyHwF5iHGfqvqCnEay0N5IMEuw2 +VgpCBpcZgWuAFGtmMpEmB/N5D9BBRUiWpI45aQTs9SCIGOR4dAJg1M5pmdy+GIyD +VcTO9o2reqAbEmBc0uq3olZfVV81JvABmQ7KX3QKI0UaQGFCUqeL/f84jrNiaO7S +ye0pTZQ6pomD4H94882kTyEtSR9YbsvP77/+bBv/gNUDd93Nn22IYSe0Hrg6eSAJ +GZR05xghFRlEtGfuDy8kEckWd6CjLdG2Vk+noKmLJIhGBBARAgAGBQJRoHvPAAoJ +EGvd/o5Uoqzxq18AnRksV8DKJTRm9vBFVxUn1x7YJPb/AJ46ujshfyV2/CRqri1W +Y61SIJNfLYkEHAQQAQIABgUCUdDbRQAKCRCxF563NH3BDc7eIACUgvlym0n1cvNk +z5itI02sycg1+RPDWsYIoMKrLzsGaTxnTn0zuu1V+jDAQT6Zhb9Uvf296KTGxnQS +NX22ViM6df7rqjkPzVlSSIuHN2GqmqXHdM76M8aqtyn246yDlI9ayVQbDLrNI8L0 +3Wx8Tdnotiu40dNLFuMX8fq8nyLTCkTVAVuns3i250gbp//ctIIbNeKQYItvBe4t +Zj+gwPJdHxX8THuiskJrAs3x2+WXuzZ/Tbpva7HqMITuSKFus5zQWO4RY+O2OpNl +wcRirtPdLy7dubzDtYNOshKi7szpwexpsMAQovaMf513K3eSWg5c3Gne8vpD0QKo +1iksjjyBFnuL0jrULlQN/K71nV0AUS03PyQdlzTubxGhK5xajiyLu9pjpIo5dq9V +sNP2LHSHGPrvvsOUh6Df/dkVnkxfpJY87RHSvqjz25OwE5KVMIWGnLvmJ9vj1Vri +dWLFhrwx/IZRNTiYJNJSbaSnljGk3n8SBe17+olIlYI1szevaJxst+7/HbOKNK7A +5Ggsi6JB4jnOiCNJ6dPIuOQHP8NCD0AL19y0SSnC1q6q75RAXw4fWzBgX5HK7psY +tsuvZw4qCsaXyCCBh7Qql8Io1m+Ugsxu1BifsI5s/I63SR/MEh23i3Scmtocmm3K +rkU5tgwXuFP1fZ9OqGsmYvlWN6q0ItdeG+9kUKs3zCGiaHqkJGvdVbtMwyx3KMkF +QqbyOkdaSff8Rkz1GDt0PTEVt4JMH8F2aAEG5WgjWwIMJlD2Knp73UfSa6jqbhlU +6M9mmGKIxbAQ3GUyfzvFE6VFPDS4B09uy0J0HCd1K0nvnKxQaX0ixEsHrpiG5IvH +teUn+DjqgVE7aBb28vYfsZB8yFl5SUVb7/7qqByeWzRmAQFJoA4pVu6kRGQG4QZb +YfE4aGLq88p4qnyJQEM7KIGBeRA6iQmTPvTTM0HgxQigUJvGrnr+SYKEXAF/ObkX +DsJunYcaNKh/JqczIg1YXc3raF+3yVcCZSDOiaipNQ1BGNKf/ko7hBM7mQJKR9Fy +VnYFzi2zAu/0FrJQWjLS7fRYlB60yl3/bWj4RxfaqXVIco0eLayVAWetsafBYC7M +ZMSIN9xzNoZQNwmTNWqVF0jRzSMonOgdTwj7R9GY/OU68a9VlXT9/s+YyUOqqOT1 +HYWrcIueaDPSTRkhEyOstg+K7m+ykG86y1GvqhWrZTqzDbPpEEoFVpLz5crQFHWK +Rs8G77h7YanhdI3+2rKrDLnolMOkgFFPdckD3aHwXTlpr9uuZ4hIhTJEBE+wFcOi +Ps4mjwdRS/9noOo4OiwTqPtu3hF6hal4q4afhTbCNajRV14Po69Sjhhz+axUtVoj +kD4LNltquQINBE3zxrgBEAColGLJYSaI+eJEQTEkpz9S4+7Tf/qoBo5mPO2jOOP7 +7ZwLLpYsMkMOtDWhiyMer6uLf49XrLJltCG4CNMbUUWIMhDEDA+iXhFOU1PljRBv +zJfNZI3sWs/42/ieA32ldSjEuVwGPRa9V5DSzasLunhiYl5E9AZOjpjjqhM8HO7c +TSShExlZcKgHf6313SKm/qJeFeC24BRu4aaZRKiEB9w6XBP55vu139QmCt2EUXYK +YPAgtOUnzUDqW+V2Z6oiDFHzFu0/9DtQyZdW3anVxudeogs6xy+GNbMNFG9lu+c6 +6qvhc/GLCr9CoHWHvB5T4hyfgKy0knO+j5AWoEnQe7+adQ/6uGGyBtxzP5DotbBS +B7OB5jDyIrB2uroHnAp7IONc0E83afxyYAxWws00C2qsG5htjP1dpSPpgcHSGvf2 +BWTpz8453mXNrY644RXyGsZiXOJOwfa/TtoeK1SA78Pj2LkQ13ES7Y6GX2zR8cqK +lAwFmXKMk76X8J6hb9h4rYgSzHkJQO9TjCq705eF66K2Z76ZC9A5QE19Gea7Tx5b +/GkpvYtOt/gx6P/Png6z8A1oGGGLWevSUxHLTrBZTnjmeHQG5Nx+po5zuM8BxRxF +GLn2NI8UxgdpKV0cZOX+p/WVSUoC+DNyl5fyxBKMTgeqYAqYNh7UDyruX5E+tlYF +7wARAQABiQIfBBgBAgAJBQJN88a4AhsMAAoJEIKKwflO8mBT6cIP/RFn8rgRK1Ib +JsBl3DJPx7yHmavp52t2vN+4ZHqkhnpzbEuFT2nWSetUQJ5J9LHoSkHoHn1yGFEQ +ctlvNqR35xX3PKHrCYv6XNHkUUj3pCcQPP7aenxqzyB9tNgyz8DqbnXNbqELhPvs +60ffmsEXgq2dNO+/wbpPW1+Yd6F5Q2X1g1dlJufFpFV0RTQFaCviESMV+lTgFAON +EpDK3wnByLukABLVKVrzq/xGly6OqeP4Rh9TvSYi/x3iqv+2wn5XZ5aGTIqWHVFb +FfwqCO4US4KdVXodubegED529TfwMzgDBfADC7HNtrgEBBs9mLT5ypv9xvyJxoMN +f1ATfKucRrRDbtSwZk3sh2LgZgXb/AAC9sZi9E6OEhXaWpx+tZNFon2vfzIcpYQz +C6rFezRGAOP2asTVqdmrtJDClHttydASNP5AKzLoc+hAmNdpMxaTnAwANVKtJggM +oS+YyINISiCFNDli+qKkl2VYXa6NK9GZGiwOVrIAFCpt1F/R+/aY+gPO9Cu+ZuJY +/XKSkUqrupqrXgc1KAtkfLEc3JuirG9rbJWDLR0kStjiczm4zW3CTzS4UwF3a5vP +lMyftAvOF+/895E8HzrO3lpT6/SwUDPUTEmv3ktcq4L0ZiX3uBiBnagbi4RREILf +Vk4vo5kBKxymtUB8mUtVL19rR0zwINuZ +=f8X6 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/face-key.pgp b/contrib/gitian-downloader/face-key.pgp new file mode 100644 index 0000000..aa05163 --- /dev/null +++ b/contrib/gitian-downloader/face-key.pgp @@ -0,0 +1,54 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +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 +e0T7DjY= +=KQ8d +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config index aef614d..1d38b60 100644 --- a/contrib/gitian-downloader/linux-download-config +++ b/contrib/gitian-downloader/linux-download-config @@ -35,4 +35,24 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami + E084FE305BDF0C476F779792657EB016521670C0: + weight: 40 + name: "Rama McIntosh" + key: face + 1A2511E978239E491A096D0A828AC1F94EF26053: + weight: 40 + name: "Charles Lee" + key: coblee + EFDFCBD38FFF68B49160C7D3A1596566F87BE631: + weight: 40 + name: "Anton Yemelyanov" + key: aspect + 59CAF0E96F23F53747945FD4FE3348877809386C: + weight: 40 + name: "Adrian Gallagher" + key: thrasher minimum_weight: 120 diff --git a/contrib/gitian-downloader/thrasher-key.pgp b/contrib/gitian-downloader/thrasher-key.pgp new file mode 100644 index 0000000..14da2c7 --- /dev/null +++ b/contrib/gitian-downloader/thrasher-key.pgp @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +mQENBFHBpq4BCAClUHF5fvpm1V0dxM1QKenkqeOl7w0EJ2MSZ26nzzH22yVOvwED +5h/7/Lb+o6QyPf/89uEPsPi4paPzgkDPT+CoZAkjKyzWy2YW/m2wHWoXWw1xSJql +qxFogmrq3ZHbjnxYOjAA4KsGpIijbLUAxOaAl5dkOCDEFl0KiKZzrXJNnYlbFef0 +fqj10QVW+o5uV9wYH6UMoc2x4yVucpLyJJVy25Qz33dqcG+nYdsT+jAPVG2Fcig/ +WlHZ2fQFloH3mThOa6PIHbym1YzjzLRLXH/oobE9RASpdwbsivVTUfq49B7BecKC +uwPRCWnv5es+dfRZrPsoipckB3ZNLQIy618TABEBAAG0MUFkcmlhbiBHYWxsYWdo +ZXIgPHRocmFzaGVyQGFkZGljdGlvbnNvZnR3YXJlLmNvbT6JATgEEwECACIFAlHB +pq4CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEP4zSId4CThs/5AH/3jY +S6hF3P2IuXfmsO8WGxcZNHx+aTwDcAdpAr4PQ9aZWXbPwBD9cDxbqJkFA604cZfT +2YrL0sRrNXyz9auFTaSxM6nWsGuI60yd2+R+DfRo7irAsJgCG1Tzx5XYOuQXlhqh +Spq4tnv5lNvJczBlijC2G7uX7bUKvPN+AqmqWMuCcS7Pezrb5d0x5JJKQhw4g+ch +Qj8bmD57kFELYq4yXVx7Wraitgn8l+pzRBTVEwAyoyNoeLiGACx8IehFx/P67LFC +tmmCaaN9U7XGX77frhzEgphK9w1rvxdd8Va1F8agAdykcztxyG5tNn1HwwGk+xA5 +482nlDKQv6U6thi44Z65AQ0EUcGmrgEIAOGydbByhDehHAFYIRTEkxnd3LGxFR+S +hmyPMCobSCgbYS6SEq9Y1+X9zcvm5dB6lnTglqV3XIznl13RTAIwLwIdLCks4KE/ +smhGHMn4/gxddQOSJg+jdSBsIwhFnfU0y5ZOYtXXpkmaUZaMq2cBkgka17nqTsd4 +DPYZasErFc/Jlqllwlr4uynLJ1I9FZ2LA9Xzx3thIHByNFXdjxKPD0sT910i3h9A +TJ4Q7sJJ/Ir7okOwrGzGVAWQvMaGj85Fq7XJNLCSd3bXaXAskYlUryJijQAWjhvq +R9mcVZz4TLjI5TyGXatYqE8B/euovYsD8HoRDgVAtsQDimkuS8Xx0R8AEQEAAYkB +HwQYAQIACQUCUcGmrgIbDAAKCRD+M0iHeAk4bHGwB/96uN7K1MVO8dKQeq2avhrH +QZCczGXB/0gRhWNj6njBJMdsfOtPypSqLWuCCN107TRJkig+77lQ8JFhRGo+5QNt +76fQL9a/VFbm1gTsAy3uL4hasHTUIrY7Uq1nDX6poHd25wXWdEBbtiwAoCjp/gid +o69WS5lsga0S2e/IySx6Tel1pUO1hYUhUzSZYVFUjM/ncPJih+VMT/3+kB4iY/Sc +eNTx85gJSnucL+mXDuZTvxXui5tt4zGxSp+POHXBDduZliyxzKr5FTPGXw493DiM +3KggSieIDL6x3BWZR2U97w0iDbGWxS5mMJt+6FNCBJmeK2ooFRT+IJ6zeoXM0z6s +=hamx +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/win32-download-config b/contrib/gitian-downloader/win32-download-config index 0f7032e..f7b5c84 100644 --- a/contrib/gitian-downloader/win32-download-config +++ b/contrib/gitian-downloader/win32-download-config @@ -35,4 +35,24 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami + E084FE305BDF0C476F779792657EB016521670C0: + weight: 40 + name: "Rama McIntosh" + key: face + 1A2511E978239E491A096D0A828AC1F94EF26053: + weight: 40 + name: "Charles Lee" + key: coblee + EFDFCBD38FFF68B49160C7D3A1596566F87BE631: + weight: 40 + name: "Anton Yemelyanov" + key: aspect + 59CAF0E96F23F53747945FD4FE3348877809386C: + weight: 40 + name: "Adrian Gallagher" + key: thrasher minimum_weight: 120 diff --git a/contrib/gitian-downloader/wtogami-key.pgp b/contrib/gitian-downloader/wtogami-key.pgp new file mode 100644 index 0000000..e0f6c4c --- /dev/null +++ b/contrib/gitian-downloader/wtogami-key.pgp @@ -0,0 +1,131 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +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 +=icdI +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/macdeploy/background.png b/contrib/macdeploy/background.png index a50a0ba607a1180dded7b5fceb3348ab55a16e5c..045fc24ddde9e83b62123d805950de3a00869544 100644 GIT binary patch literal 13651 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 literal 16827 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 diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index e159f9b..d24bd10 100644 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -18,6 +18,7 @@ # import subprocess, sys, re, os, shutil, stat, os.path +from string import Template from time import sleep from argparse import ArgumentParser @@ -169,7 +170,12 @@ class DeploymentInfo(object): elif os.path.exists(os.path.join(parentDir, "share", "qt4", "translations")): # MacPorts layout, e.g. "/opt/local/share/qt4" self.qtPath = os.path.join(parentDir, "share", "qt4") - + elif os.path.exists(os.path.join(os.path.dirname(parentDir), "share", "qt4", "translations")): + # Newer Macports layout + self.qtPath = os.path.join(os.path.dirname(parentDir), "share", "qt4") + else: + self.qtPath = os.getenv("QTDIR", None) + if self.qtPath is not None: pluginPath = os.path.join(self.qtPath, "plugins") if os.path.exists(pluginPath): @@ -239,7 +245,11 @@ def runStrip(binaryPath, verbose): subprocess.check_call(["strip", "-x", binaryPath]) def copyFramework(framework, path, verbose): - fromPath = framework.sourceFilePath + if framework.sourceFilePath.startswith("Qt"): + #standard place for Nokia Qt installer's frameworks + fromPath = "/Library/Frameworks/" + framework.sourceFilePath + else: + fromPath = framework.sourceFilePath toDir = os.path.join(path, framework.destinationDirectory) toPath = os.path.join(toDir, framework.binaryName) @@ -342,7 +352,7 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): if pluginDirectory == "designer": # Skip designer plugins continue - elif pluginDirectory == "phonon": + elif pluginDirectory == "phonon" or pluginDirectory == "phonon_backend": # Deploy the phonon plugins only if phonon is in use if not deploymentInfo.usesFramework("phonon"): continue @@ -420,12 +430,17 @@ ap = ArgumentParser(description="""Improved version of macdeployqt. Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file. Note, that the "dist" folder will be deleted before deploying on each run. -Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.""") +Optionally, Qt translation files (.qm) and additional resources can be added to the bundle. + +Also optionally signs the .app bundle; set the CODESIGNARGS environment variable to pass arguments +to the codesign tool. +E.g. CODESIGNARGS='--sign "Developer ID Application: ..." --keychain /encrypted/foo.keychain'""") ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed") ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug") ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment") ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries") +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") @@ -626,6 +641,15 @@ for p in config.add_resources: # ------------------------------------------------ +if config.sign and 'CODESIGNARGS' not in os.environ: + print "You must set the CODESIGNARGS environment variable. Skipping signing." +elif config.sign: + if verbose >= 1: + print "Code-signing app bundle %s"%(target,) + subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True) + +# ------------------------------------------------ + if config.dmg is not None: def runHDIUtil(verb, image_basename, **kwargs): hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] @@ -704,31 +728,68 @@ if config.dmg is not None: if fancy.get("applications_symlink", False): os.symlink("/Applications", os.path.join(disk_root, "Applications")) - finder = appscript.app("Finder") - disk = finder.disks[disk_name] - disk.open() - window = disk.container_window - window.current_view.set(appscript.k.icon_view) - window.toolbar_visible.set(False) - window.statusbar_visible.set(False) - if fancy.has_key("window_bounds"): - window.bounds.set(fancy["window_bounds"]) - view_options = window.icon_view_options - view_options.arrangement.set(appscript.k.not_arranged) - if fancy.has_key("icon_size"): - view_options.icon_size.set(fancy["icon_size"]) - if bg_path is not None: - view_options.background_picture.set(disk.files[os.path.basename(bg_path)]) + # The Python appscript package broke with OSX 10.8 and isn't being fixed. + # So we now build up an AppleScript string and use the osascript command + # to make the .dmg file pretty: + appscript = Template( """ + on run argv + tell application "Finder" + tell disk "$disk" + open + set current view of container window to icon view + set toolbar visible of container window to false + set statusbar visible of container window to false + set the bounds of container window to {$window_bounds} + set theViewOptions to the icon view options of container window + set arrangement of theViewOptions to not arranged + set icon size of theViewOptions to $icon_size + $background_commands + $items_positions + close -- close/reopen works around a bug... + open + update without registering applications + delay 5 + eject + end tell + end tell + end run + """) + + itemscript = Template('set position of item "${item}" of container window to {${position}}') + items_positions = [] if fancy.has_key("items_position"): for name, position in fancy["items_position"].iteritems(): - window.items[name].position.set(position) - disk.close() + params = { "item" : name, "position" : ",".join([str(p) for p in position]) } + items_positions.append(itemscript.substitute(params)) + + params = { + "disk" : "CasinoCoin-Qt", + "window_bounds" : "300,300,800,620", + "icon_size" : "96", + "background_commands" : "", + "items_positions" : "\n ".join(items_positions) + } + if fancy.has_key("window_bounds"): + params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]]) + if fancy.has_key("icon_size"): + params["icon_size"] = str(fancy["icon_size"]) if bg_path is not None: - subprocess.call(["SetFile", "-a", "V", bg_path]) - disk.update(registering_applications=False) - sleep(2) - disk.eject() - + # Set background file, then call SetFile to make it invisible. + # (note: making it invisible first makes set background picture fail) + bgscript = Template("""set background picture of theViewOptions to file "$bgpic" + do shell script "SetFile -a V /Volumes/$disk/$bgpic" """) + params["background_commands"] = bgscript.substitute({"bgpic" : os.path.basename(bg_path), "disk" : params["disk"]}) + + s = appscript.substitute(params) + if verbose >= 2: + print("Running AppleScript:") + print(s) + + p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE) + p.communicate(input=s) + if p.returncode: + print("Error running osascript.") + if verbose >= 2: print "+ Finalizing .dmg disk image +" diff --git a/contrib/macdeploy/notes.txt b/contrib/macdeploy/notes.txt index a3f0b54..3d74901 100644 --- a/contrib/macdeploy/notes.txt +++ b/contrib/macdeploy/notes.txt @@ -5,7 +5,7 @@ Python 2.7 and make it your default Python installation. You will need the appscript package for the fancy disk image creation to work. Install it by invoking "sudo easy_install appscript". -Ths script should be invoked in the target directory like this: +This script should be invoked in the target directory like this: $source_dir/contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy $source_dir/contrib/macdeploy/fancy.plist -verbose 2 During the process, the disk image window will pop up briefly where the fancy diff --git a/contrib/pyminer/example-config.cfg b/contrib/pyminer/example-config.cfg index 103e7c1..4edbe34 100644 --- a/contrib/pyminer/example-config.cfg +++ b/contrib/pyminer/example-config.cfg @@ -3,7 +3,7 @@ # RPC login details # host=127.0.0.1 -port=8332 +port=47970 rpcuser=myusername rpcpass=mypass diff --git a/contrib/pyminer/pyminer.py b/contrib/pyminer/pyminer.py index 2887aba..1bbdd28 100644 --- a/contrib/pyminer/pyminer.py +++ b/contrib/pyminer/pyminer.py @@ -2,7 +2,7 @@ # # Copyright (c) 2011 The Bitcoin developers # Distributed under the MIT/X11 software license, see the accompanying -# file license.txt or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or http://www.opensource.org/licenses/mit-license.php. # import time @@ -217,7 +217,7 @@ if __name__ == '__main__': if 'host' not in settings: settings['host'] = '127.0.0.1' if 'port' not in settings: - settings['port'] = 8332 + settings['port'] = 47970 if 'threads' not in settings: settings['threads'] = 1 if 'hashmeter' not in settings: diff --git a/contrib/seeds/README b/contrib/seeds/README new file mode 100644 index 0000000..97e3e1e --- /dev/null +++ b/contrib/seeds/README @@ -0,0 +1,9 @@ +Utility to generate the pnSeed[] array that is compiled into the client +(see src/net.cpp). + +The 600 seeds compiled into the 0.8 release were created from sipa's DNS seed data, like this: + +curl -s http://bitcoin.sipa.be/seeds.txt | head -1000 | makeseeds.py + +The input to makeseeds.py is assumed to be approximately sorted from most-reliable to least-reliable, +with IP:port first on each line (lines that don't match IPv4:port are ignored). diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py new file mode 100644 index 0000000..a7dfcf9 --- /dev/null +++ b/contrib/seeds/makeseeds.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# +# Generate pnSeed[] from Pieter's DNS seeder +# + +NSEEDS=600 + +import re +import sys +from subprocess import check_output + +def main(): + lines = sys.stdin.readlines() + + ips = [] + pattern = re.compile(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}):47950") + for line in lines: + m = pattern.match(line) + if m is None: + continue + ip = 0 + for i in range(0,4): + ip = ip + (int(m.group(i+1)) << (8*(i))) + if ip == 0: + continue + ips.append(ip) + + for row in range(0, min(NSEEDS,len(ips)), 8): + print " " + ", ".join([ "0x%08x"%i for i in ips[row:row+8] ]) + "," + +if __name__ == '__main__': + main() diff --git a/contrib/spendfrom/README b/contrib/spendfrom/README new file mode 100644 index 0000000..8a087a0 --- /dev/null +++ b/contrib/spendfrom/README @@ -0,0 +1,32 @@ +Use the raw transactions API to send coins received on a particular +address (or addresses). + +Depends on jsonrpc + +Usage: + +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. + +You may explictly 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 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 new file mode 100644 index 0000000..01b9768 --- /dev/null +++ b/contrib/spendfrom/setup.py @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000..ed464d2 --- /dev/null +++ b/contrib/spendfrom/spendfrom.py @@ -0,0 +1,267 @@ +#!/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'] = 17970 if testnet else 47970 + 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/test-patches/README b/contrib/test-patches/README new file mode 100644 index 0000000..ed754ce --- /dev/null +++ b/contrib/test-patches/README @@ -0,0 +1,4 @@ +These patches are applied when the automated pull-tester +tests each pull and when master is tested using jenkins. +You can find more information about the tests run at +http://jenkins.bluematt.me/pull-tester/files/ diff --git a/contrib/testgen/README b/contrib/testgen/README new file mode 100644 index 0000000..02d6c4c --- /dev/null +++ b/contrib/testgen/README @@ -0,0 +1 @@ +Utilities to generate test vectors for the data-driven Bitcoin tests diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py new file mode 100644 index 0000000..b716495 --- /dev/null +++ b/contrib/testgen/base58.py @@ -0,0 +1,104 @@ +''' +Bitcoin base58 encoding and decoding. + +Based on https://bitcointalk.org/index.php?topic=1026.0 (public domain) +''' +import hashlib + +# for compatibility with following code... +class SHA256: + new = hashlib.sha256 + +if str != bytes: + # Python 3.x + def ord(c): + return c + def chr(n): + return bytes( (n,) ) + +__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' +__b58base = len(__b58chars) +b58chars = __b58chars + +def b58encode(v): + """ encode v, which is a string of bytes, to base58. + """ + long_value = 0 + for (i, c) in enumerate(v[::-1]): + long_value += (256**i) * ord(c) + + result = '' + while long_value >= __b58base: + div, mod = divmod(long_value, __b58base) + result = __b58chars[mod] + result + long_value = div + result = __b58chars[long_value] + result + + # Bitcoin does a little leading-zero-compression: + # leading 0-bytes in the input become leading-1s + nPad = 0 + for c in v: + if c == '\0': nPad += 1 + else: break + + return (__b58chars[0]*nPad) + result + +def b58decode(v, length = None): + """ decode v into a string of len bytes + """ + long_value = 0 + for (i, c) in enumerate(v[::-1]): + long_value += __b58chars.find(c) * (__b58base**i) + + result = bytes() + while long_value >= 256: + div, mod = divmod(long_value, 256) + result = chr(mod) + result + long_value = div + result = chr(long_value) + result + + nPad = 0 + for c in v: + if c == __b58chars[0]: nPad += 1 + else: break + + result = chr(0)*nPad + result + if length is not None and len(result) != length: + return None + + return result + +def checksum(v): + """Return 32-bit checksum based on SHA256""" + return SHA256.new(SHA256.new(v).digest()).digest()[0:4] + +def b58encode_chk(v): + """b58encode a string, with 32-bit checksum""" + return b58encode(v + checksum(v)) + +def b58decode_chk(v): + """decode a base58 string, check and remove checksum""" + result = b58decode(v) + if result is None: + return None + h3 = checksum(result[:-4]) + if result[-4:] == checksum(result[:-4]): + return result[:-4] + else: + return None + +def get_bcaddress_version(strAddress): + """ Returns None if strAddress is invalid. Otherwise returns integer version of address. """ + addr = b58decode_chk(strAddress) + if addr is None or len(addr)!=21: return None + version = addr[0] + return ord(version) + +if __name__ == '__main__': + # Test case (from http://gitorious.org/bitcoin/python-base58.git) + assert get_bcaddress_version('15VjRaDX9zpbA8LVnbrCAFzrVzN7ixHNsC') is 0 + _ohai = 'o hai'.encode('ascii') + _tmp = b58encode(_ohai) + assert _tmp == 'DYB3oMS' + assert b58decode(_tmp, 5) == _ohai + print("Tests passed") diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py new file mode 100644 index 0000000..92dee87 --- /dev/null +++ b/contrib/testgen/gen_base58_test_vectors.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +''' +Generate valid and invalid base58 address and private key test vectors. + +Usage: + gen_base58_test_vectors.py valid 50 > ../../src/test/data/base58_keys_valid.json + gen_base58_test_vectors.py invalid 50 > ../../src/test/data/base58_keys_invalid.json +''' +# 2012 Wladimir J. van der Laan +# Released under MIT License +import os +from itertools import islice +from base58 import b58encode, b58decode, b58encode_chk, b58decode_chk, b58chars +import random +from binascii import b2a_hex + +# key types +PUBKEY_ADDRESS = 48 +SCRIPT_ADDRESS = 5 +PUBKEY_ADDRESS_TEST = 111 +SCRIPT_ADDRESS_TEST = 196 +PRIVKEY = 176 +PRIVKEY_TEST = 239 + +metadata_keys = ['isPrivkey', 'isTestnet', 'addrType', 'isCompressed'] +# templates for valid sequences +templates = [ + # prefix, payload_size, suffix, metadata + # None = N/A + ((PUBKEY_ADDRESS,), 20, (), (False, False, 'pubkey', None)), + ((SCRIPT_ADDRESS,), 20, (), (False, False, 'script', None)), + ((PUBKEY_ADDRESS_TEST,), 20, (), (False, True, 'pubkey', None)), + ((SCRIPT_ADDRESS_TEST,), 20, (), (False, True, 'script', None)), + ((PRIVKEY,), 32, (), (True, False, None, False)), + ((PRIVKEY,), 32, (1,), (True, False, None, True)), + ((PRIVKEY_TEST,), 32, (), (True, True, None, False)), + ((PRIVKEY_TEST,), 32, (1,), (True, True, None, True)) +] + +def is_valid(v): + '''Check vector v for validity''' + 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])) + if result.startswith(prefix) and result.endswith(suffix): + if (len(result) - len(prefix) - len(suffix)) == template[1]: + return True + return False + +def gen_valid_vectors(): + '''Generate valid test vectors''' + while True: + for template in templates: + prefix = str(bytearray(template[0])) + payload = os.urandom(template[1]) + suffix = str(bytearray(template[2])) + rv = b58encode_chk(prefix + payload + suffix) + assert is_valid(rv) + metadata = dict([(x,y) for (x,y) in zip(metadata_keys,template[3]) if y is not None]) + yield (rv, b2a_hex(payload), metadata) + +def gen_invalid_vector(template, corrupt_prefix, randomize_payload_size, corrupt_suffix): + '''Generate possibly invalid vector''' + if corrupt_prefix: + prefix = os.urandom(1) + else: + prefix = str(bytearray(template[0])) + + if randomize_payload_size: + payload = os.urandom(max(int(random.expovariate(0.5)), 50)) + else: + payload = os.urandom(template[1]) + + if corrupt_suffix: + suffix = os.urandom(len(template[2])) + else: + suffix = str(bytearray(template[2])) + + return b58encode_chk(prefix + payload + suffix) + +def randbool(p = 0.5): + '''Return True with P(p)''' + return random.random() < p + +def gen_invalid_vectors(): + '''Generate invalid test vectors''' + # start with some manual edge-cases + yield "", + yield "x", + while True: + # kinds of invalid vectors: + # invalid prefix + # invalid payload length + # invalid (randomized) suffix (add random data) + # corrupt checksum + for template in templates: + val = gen_invalid_vector(template, randbool(0.2), randbool(0.2), randbool(0.2)) + if random.randint(0,10)<1: # line corruption + if randbool(): # add random character to end + val += random.choice(b58chars) + else: # replace random character in the middle + n = random.randint(0, len(val)) + val = val[0:n] + random.choice(b58chars) + val[n+1:] + if not is_valid(val): + yield val, + +if __name__ == '__main__': + import sys, json + iters = {'valid':gen_valid_vectors, 'invalid':gen_invalid_vectors} + try: + uiter = iters[sys.argv[1]] + except IndexError: + uiter = gen_valid_vectors + try: + count = int(sys.argv[2]) + except IndexError: + count = 0 + + data = list(islice(uiter(), count)) + json.dump(data, sys.stdout, sort_keys=True, indent=4) + sys.stdout.write('\n') + diff --git a/contrib/tidy_datadir.sh b/contrib/tidy_datadir.sh new file mode 100644 index 0000000..5d6d826 --- /dev/null +++ b/contrib/tidy_datadir.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +if [ -d "$1" ]; then + cd "$1" +else + echo "Usage: $0 " >&2 + echo "Removes obsolete Bitcoin database files" >&2 + exit 1 +fi + +LEVEL=0 +if [ -f wallet.dat -a -f addr.dat -a -f blkindex.dat -a -f blk0001.dat ]; then LEVEL=1; fi +if [ -f wallet.dat -a -f peers.dat -a -f blkindex.dat -a -f blk0001.dat ]; then LEVEL=2; fi +if [ -f wallet.dat -a -f peers.dat -a -f coins/CURRENT -a -f blktree/CURRENT -a -f blocks/blk00000.dat ]; then LEVEL=3; fi +if [ -f wallet.dat -a -f peers.dat -a -f chainstate/CURRENT -a -f blocks/index/CURRENT -a -f blocks/blk00000.dat ]; then LEVEL=4; fi + +case $LEVEL in + 0) + echo "Error: no Bitcoin datadir detected." + exit 1 + ;; + 1) + echo "Detected old Bitcoin datadir (before 0.7)." + echo "Nothing to do." + exit 0 + ;; + 2) + echo "Detected Bitcoin 0.7 datadir." + ;; + 3) + echo "Detected Bitcoin pre-0.8 datadir." + ;; + 4) + echo "Detected Bitcoin 0.8 datadir." + ;; +esac + +FILES="" +DIRS="" + +if [ $LEVEL -ge 3 ]; then FILES=$(echo $FILES blk????.dat blkindex.dat); fi +if [ $LEVEL -ge 2 ]; then FILES=$(echo $FILES addr.dat); fi +if [ $LEVEL -ge 4 ]; then DIRS=$(echo $DIRS coins blktree); fi + +for FILE in $FILES; do + if [ -f $FILE ]; then + echo "Deleting: $FILE" + rm -f $FILE + fi +done + +for DIR in $DIRS; do + if [ -d $DIR ]; then + echo "Deleting: $DIR/" + rm -rf $DIR + fi +done + +echo "Done." diff --git a/contrib/wallettools/.svn/entries b/contrib/wallettools/.svn/entries new file mode 100644 index 0000000..e270135 --- /dev/null +++ b/contrib/wallettools/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +114 +svn://svn.greyhatapps.com/repos/projects/casinocoin/contrib/wallettools +svn://svn.greyhatapps.com/repos/projects + + + +2013-07-03T07:48:00.318239Z +64 +nam + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +1324ab70-8081-43f4-a012-72ad25adf38d + +walletchangepass.py +file + + + + +2013-06-25T14:29:02.000000Z +55504fcb6f0cc00002491d0f84ab69a6 +2013-07-03T07:48:00.318239Z +64 +nam + + + + + + + + + + + + + + + + + + + + + +219 + +walletunlock.py +file + + + + +2013-06-25T14:29:02.000000Z +fc0493c5e7b1aaf7554a8220b134f65b +2013-07-03T07:48:00.318239Z +64 +nam + + + + + + + + + + + + + + + + + + + + + +157 + diff --git a/contrib/wallettools/.svn/text-base/walletchangepass.py.svn-base b/contrib/wallettools/.svn/text-base/walletchangepass.py.svn-base new file mode 100644 index 0000000..30f3f5b --- /dev/null +++ b/contrib/wallettools/.svn/text-base/walletchangepass.py.svn-base @@ -0,0 +1,5 @@ +from jsonrpc import ServiceProxy +access = ServiceProxy("http://127.0.0.1:8332") +pwd = raw_input("Enter old wallet passphrase: ") +pwd2 = raw_input("Enter new wallet passphrase: ") +access.walletpassphrasechange(pwd, pwd2) \ No newline at end of file diff --git a/contrib/wallettools/.svn/text-base/walletunlock.py.svn-base b/contrib/wallettools/.svn/text-base/walletunlock.py.svn-base new file mode 100644 index 0000000..f847c6f --- /dev/null +++ b/contrib/wallettools/.svn/text-base/walletunlock.py.svn-base @@ -0,0 +1,4 @@ +from jsonrpc import ServiceProxy +access = ServiceProxy("http://127.0.0.1:8332") +pwd = raw_input("Enter wallet passphrase: ") +access.walletpassphrase(pwd, 60) \ No newline at end of file diff --git a/contrib/wallettools/walletchangepass.py b/contrib/wallettools/walletchangepass.py index 30f3f5b..372c2e7 100644 --- a/contrib/wallettools/walletchangepass.py +++ b/contrib/wallettools/walletchangepass.py @@ -1,5 +1,5 @@ from jsonrpc import ServiceProxy -access = ServiceProxy("http://127.0.0.1:8332") +access = ServiceProxy("http://127.0.0.1:47970") pwd = raw_input("Enter old wallet passphrase: ") pwd2 = raw_input("Enter new wallet passphrase: ") -access.walletpassphrasechange(pwd, pwd2) \ No newline at end of file +access.walletpassphrasechange(pwd, pwd2) diff --git a/contrib/wallettools/walletunlock.py b/contrib/wallettools/walletunlock.py index f847c6f..331a3c7 100644 --- a/contrib/wallettools/walletunlock.py +++ b/contrib/wallettools/walletunlock.py @@ -1,4 +1,4 @@ from jsonrpc import ServiceProxy -access = ServiceProxy("http://127.0.0.1:8332") +access = ServiceProxy("http://127.0.0.1:47970") pwd = raw_input("Enter wallet passphrase: ") -access.walletpassphrase(pwd, 60) \ No newline at end of file +access.walletpassphrase(pwd, 60) diff --git a/doc/Doxyfile b/doc/Doxyfile index 08d4f8c..973125a 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -28,7 +28,7 @@ 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 +PROJECT_NAME = CasinoCoin # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or @@ -203,7 +203,7 @@ TAB_SIZE = 8 # 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. +# You can put \n in the value part of an alias to insert newlines. ALIASES = diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..cc0ecc2 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,47 @@ +CasinoCoin 0.8.x BETA +==================== + +Copyright (c) 2009-2013 Bitcoin Developers +Copyright (c) 2011-2013 CasinoCoin Developers + +Distributed under the MIT/X11 software license, see the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://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. + + +Intro +--------------------- +CasinoCoin 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. + + +Setup +--------------------- +You need the Qt4 run-time libraries to run CasinoCoin-Qt. On Debian or Ubuntu: + `sudo apt-get install libqtgui4` + +Unpack the files into a directory and run: + +- bin/32/casinocoin-qt (GUI, 32-bit) +- bin/32/casinocoind (headless, 32-bit) +- bin/64/casinocoin-qt (GUI, 64-bit) +- bin/64/casinocoind (headless, 64-bit) + +See the documentation at the [CasinoCoin Wiki](http://casinocoin.info) +for help and more information. + + +Other Pages +--------------------- +- [Unix Build Notes](build-unix.md) +- [OSX Build Notes](build-osx.md) +- [Windows Build Notes](build-msw.md) +- [Coding Guidelines](coding.md) +- [Release Process](release-process.md) +- [Release Notes](release-notes.md) +- [Multiwallet Qt Development](multiwallet-qt.md) +- [Unit Tests](unit-tests.md) +- [Translation Process](translation_process.md) diff --git a/doc/README_windows.txt b/doc/README_windows.txt index 4aa9135..88ae59d 100644 --- a/doc/README_windows.txt +++ b/doc/README_windows.txt @@ -1,8 +1,7 @@ -CasinoCoin 0.6 BETA +CasinoCoin 0.8.x BETA -Copyright (c) 2009-2012 Bitcoin Developers -Copyright (c) 2011-2012 Litecoin Developers -Copyright (c) 2013 CasinoCoin Developers +Copyright (c) 2009-2013 Bitcoin Developers +Copyright (c) 2011-2013 CasinoCoin Developers Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in @@ -22,16 +21,8 @@ Setup ----- Unpack the files into a directory and run casinocoin-qt.exe. -If you have Microsoft Security Essentials, you need to add casinocoin-qt.exe to its -"Excluded processes" list. Microsoft Security Essentials->Settings tab, -select Excluded processes, press Add, select casinocoin-qt.exe, OK, Save changes. +CasinoCoin-Qt is the original CasinoCoin client and it builds the backbone of the network. +However, it downloads and stores the entire history of CasinoCoin transactions; +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. -The software automatically finds other nodes to connect to. You can -enable Universal Plug and Play using a menu entry or set your firewall -to forward port 9333 (TCP) to your computer so you can receive -incoming connections. CasinoCoin works without incoming connections, -but allowing incoming connections helps the CasinoCoin network. - -See the bitcoin wiki at: - https://en.bitcoin.it/wiki/Main_Page -for more help and information. diff --git a/doc/Tor.txt b/doc/Tor.txt index 174d354..6894028 100644 --- a/doc/Tor.txt +++ b/doc/Tor.txt @@ -1,19 +1,19 @@ TOR SUPPORT IN BITCOIN ====================== -It is possible to run Bitcoin as a Tor hidden service, and connect to such services. +It is possible to run CasinoCoin as a Tor hidden service, and connect to such services. -The following assumes you have a Tor proxy running on port 9050. Many distributions +The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on a random port. See https://www.torproject.org/docs/faq.html.en#TBBSocksPort for how to properly configure Tor. -1. Run bitcoin behind a Tor proxy +1. Run casinocoin behind a Tor proxy --------------------------------- -The first step is running Bitcoin behind a Tor proxy. This will already make all +The first step is running CasinoCoin behind a Tor proxy. This will already make all outgoing connections be anonimized, but more is possible. -socks=5 SOCKS5 supports connecting-to-hostname, which can be used instead @@ -28,10 +28,6 @@ outgoing connections be anonimized, but more is possible. need to set this if it's the same as -proxy. You can use -notor to explicitly disable access to hidden service. --dnsseed DNS seeds are not resolved directly when a SOCKS5 proxy server is - set. Rather, a short-lived proxy connection to the dns seed - hostname is attempted, and peer addresses are requested. - -listen When using -proxy, listening is disabled by default. If you want to run a hidden service (see next section), you'll need to enable it explicitly. @@ -43,26 +39,26 @@ outgoing connections be anonimized, but more is possible. In a typical situation, this suffices to run behind a Tor proxy: - ./bitcoin -proxy=127.0.0.1:9050 + ./casinocoind -proxy=127.0.0.1:9050 -2. Run a bitcoin hidden server +2. Run a casinocoin hidden server ------------------------------ If you configure your Tor system accordingly, it is possible to make your node also reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent config file): - HiddenServiceDir /var/lib/tor/bitcoin-service/ - HiddenServicePort 9333 127.0.0.1:9333 + HiddenServiceDir /var/lib/tor/casinocoin-service/ + HiddenServicePort 47950 127.0.0.1:47950 -The directory can be different of course, but (both) 9333's should be equal to your -bitcoind's P2P listen port (9333 by default). +The directory can be different of course, but (both) port numbers should be equal to +your casinocoind's P2P listen port (47950 by default). --externalip=X You can tell bitcoin about its publicly reachable address using +-externalip=X You can tell casinocoin about its publicly reachable address using this option, and this can be a .onion address. Given the above configuration, you can find your onion address in - /var/lib/tor/bitcoin-service/hostname. Onion addresses are given + /var/lib/tor/casinocoin-service/hostname. Onion addresses are given preference for your node to advertize itself with, for connections coming from unroutable addresses (such as 127.0.0.1, where the Tor proxy typically runs). @@ -79,18 +75,18 @@ bitcoind's P2P listen port (9333 by default). In a typical situation, where you're only reachable via Tor, this should suffice: - ./bitcoind -proxy=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -listen + ./casinocoind -proxy=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -listen -(obviously replace the Onion address with your own). If you don't care too much +(obviously, replace the Onion address with your own). If you don't care too much about hiding your node, and want to be reachable on IPv4 as well, additionally specify: - ./bitcoind ... -discover + ./casinocoind ... -discover -and open port 9333 on your firewall (or use -upnp). +and open port 47950 on your firewall (or use -upnp). If you only want to use Tor to reach onion addresses, but not use it as a proxy for normal IPv4/IPv6 communication, use: - ./bitcoin -tor=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover + ./casinocoind -tor=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover diff --git a/doc/assets-attribution.txt b/doc/assets-attribution.txt index e5936ee..2069c5d 100644 --- a/doc/assets-attribution.txt +++ b/doc/assets-attribution.txt @@ -1,9 +1,8 @@ -Code: src/strlcpy.h -Author: Todd C. Miller -License: ISC - Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, - src/qt/res/src/*.svg + src/qt/res/src/clock_green.svg, src/qt/res/src/clock1.svg, + src/qt/res/src/clock2.svg, src/qt/res/src/clock3.svg, + src/qt/res/src/clock4.svg, src/qt/res/src/clock5.svg, + src/qt/res/src/inout.svg, src/qt/res/src/questionmark.svg Designer: Wladimir van der Laan License: MIT @@ -29,6 +28,7 @@ Designer: md2k7 Site: https://bitcointalk.org/index.php?topic=15276.0 License: You are free to do with these icons as you wish, including selling, copying, modifying etc. +License: MIT Icon: src/qt/res/icons/configure.png, src/qt/res/icons/quit.png, src/qt/res/icons/editcopy.png, src/qt/res/icons/editpaste.png, @@ -38,23 +38,21 @@ Designer: http://www.everaldo.com Icon Pack: Crystal SVG License: LGPL -Icon: src/qt/res/icons/bitcoin.png, src/qt/res/icons/toolbar.png -Designer: BitcoinPorn (forum) -License: Public Domain -Site: https://bitcointalk.org/index.php?topic=47417.msg591988#msg591988 - -Icon: scripts/img/reload.xcf (modified),src/qt/res/movies/update_spinner.mng +Icon: scripts/img/reload.xcf (modified), src/qt/res/movies/update_spinner.mng Icon Pack: Kids Designer: Everaldo (Everaldo Coelho) License: GNU/GPL Site: http://findicons.com/icon/17102/reload?id=17102 -Image: src/qt/res/images/splash2.jpg (Wallet image) -Designer: Crobbo (forum), adapted to CasinoCoin by BitcoinPorn (forum) -Site: https://bitcointalk.org/index.php?topic=32273.0, https://bitcointalk.org/index.php?topic=47417.msg591988#msg591988 -License: Public domain - Icon: src/qt/res/icons/debugwindow.png Designer: Vignoni David Site: http://www.oxygen-icons.org/ License: Oxygen icon theme is dual licensed. You may copy it under the Creative Common Attribution-ShareAlike 3.0 License or the GNU Library General Public License. + +Icon: src/qt/res/icons/bitcoin.icns, src/qt/res/src/bitcoin.svg, + src/qt/res/src/bitcoin.ico, src/qt/res/src/bitcoin.png, + src/qt/res/src/bitcoin_testnet.png, docs/bitcoin_logo_doxygen.png, + src/qt/res/icons/toolbar.png, src/qt/res/icons/toolbar_testnet.png, + src/qt/res/images/splash.png, src/qt/res/images/splash_testnet.png +Designer: Jonas Schnelli (based on the original bitcoin logo from Bitboy) +License: MIT diff --git a/doc/bitcoin_logo_doxygen.png b/doc/bitcoin_logo_doxygen.png index 5b41b02e18e57e42ba6ee790ca69e88439ea09c0..2d62a8dc8ab03ce1cf65addc0d2cb03eef3ece15 100644 GIT binary patch literal 4757 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 diff --git a/doc/build-msw.md b/doc/build-msw.md new file mode 100644 index 0000000..2063788 --- /dev/null +++ b/doc/build-msw.md @@ -0,0 +1,89 @@ +Copyright (c) 2009-2013 Bitcoin Developers +Distributed under the MIT/X11 software license, see the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://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. + + +See readme-qt.rst for instructions on building CasinoCoin-Qt, the +graphical user interface. + +WINDOWS BUILD NOTES +=================== + +Compilers Supported +------------------- +TODO: What works? +Note: releases are cross-compiled using mingw running on Linux. + + +Dependencies +------------ +Libraries you need to download separately and build: + + default path download +OpenSSL \openssl-1.0.1c-mgw http://www.openssl.org/source/ +Berkeley DB \db-4.8.30.NC-mgw http://www.oracle.com/technology/software/products/berkeley-db/index.html +Boost \boost-1.50.0-mgw http://www.boost.org/users/download/ +miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/ + +Their licenses: + + OpenSSL Old BSD license with the problematic advertising requirement + Berkeley DB New BSD license with additional requirement that linked software must be free open source + Boost MIT-like license + miniupnpc New (3-clause) BSD license + +Versions used in this release: + + OpenSSL 1.0.1c + Berkeley DB 4.8.30.NC + Boost 1.50.0 + miniupnpc 1.6 + + +OpenSSL +------- +MSYS shell: + +un-tar sources with MSYS 'tar xfz' to avoid issue with symlinks (OpenSSL ticket 2377) +change 'MAKE' env. variable from 'C:\MinGW32\bin\mingw32-make.exe' to '/c/MinGW32/bin/mingw32-make.exe' + + cd /c/openssl-1.0.1c-mgw + ./config + make + +Berkeley DB +----------- +MSYS shell: + + cd /c/db-4.8.30.NC-mgw/build_unix + sh ../dist/configure --enable-mingw --enable-cxx + make + +Boost +----- +DOS prompt: + + downloaded boost jam 3.1.18 + cd \boost-1.50.0-mgw + bjam toolset=gcc --build-type=complete stage + +MiniUPnPc +--------- +UPnP support is optional, make with `USE_UPNP=` to disable it. + +MSYS shell: + + cd /c/miniupnpc-1.6-mgw + make -f Makefile.mingw + mkdir miniupnpc + cp *.h miniupnpc/ + +CasinoCoin +------- +DOS prompt: + + cd \casinocoin\src + mingw32-make -f makefile.mingw + strip casinocoind.exe diff --git a/doc/build-osx.md b/doc/build-osx.md new file mode 100644 index 0000000..47aaf48 --- /dev/null +++ b/doc/build-osx.md @@ -0,0 +1,185 @@ +Mac OS X casinocoind build instructions +==================================== + +Authors +------- + +* Laszlo Hanyecz +* Douglas Huff +* Colin Dean +* Gavin Andresen + +License +------- + +Copyright (c) 2009-2012 Bitcoin Developers + +Distributed under the MIT/X11 software license, see the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in +the OpenSSL Toolkit (http://www.openssl.org/). + +This product includes cryptographic software written by +Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + +Notes +----- + +See `doc/readme-qt.rst` for instructions on building CasinoCoin-Qt, the +graphical user interface. + +Tested on OS X 10.5 through 10.8 on Intel processors only. PPC is not +supported because it is big-endian. + +All of the commands should be executed in a Terminal application. The +built-in one is located in `/Applications/Utilities`. + +Preparation +----------- + +You need to install XCode with all the options checked so that the compiler +and everything is available in /usr not just /Developer. XCode should be +available on your OS X installation media, but if not, you can get the +current version from https://developer.apple.com/xcode/. If you install +Xcode 4.3 or later, you'll need to install its command line tools. This can +be done in `Xcode > Preferences > Downloads > Components` and generally must +be re-done or updated every time Xcode is updated. + +There's an assumption that you already have `git` installed, as well. If +not, it's the path of least resistance to install [Github for Mac](https://mac.github.com/) +(OS X 10.7+) or +[Git for OS X](https://code.google.com/p/git-osx-installer/). It is also +available via Homebrew or MacPorts. + +You will also need to install [Homebrew](http://mxcl.github.io/homebrew/) +or [MacPorts](https://www.macports.org/) in order to install library +dependencies. It's largely a religious decision which to choose, but, as of +December 2012, MacPorts is a little easier because you can just install the +dependencies immediately - no other work required. If you're unsure, read +the instructions through first in order to assess what you want to do. +Homebrew is a little more popular among those newer to OS X. + +The installation of the actual dependencies is covered in the Instructions +sections below. + +Instructions: MacPorts +---------------------- + +### Install dependencies + +Installing the dependencies using MacPorts is very straightforward. + + sudo port install boost db48@+no_java openssl miniupnpc + +### Building `casinocoind` + +1. Clone the github tree to get the source code and go into the directory. + + git clone git@github.com:casinocoin-project/casinocoin.git casinocoin + cd casinocoin + +2. Build casinocoind: + + cd src + make -f makefile.osx + +3. It is a good idea to build and run the unit tests, too: + + make -f makefile.osx test + +Instructions: HomeBrew +---------------------- + +#### Install dependencies using Homebrew + + brew install boost miniupnpc openssl berkeley-db4 + +Note: After you have installed the dependencies, you should check that the Brew installed version of OpenSSL is the one available for compilation. You can check this by typing + + openssl version + +into Terminal. You should see OpenSSL 1.0.1e 11 Feb 2013. + +If not, you can ensure that the Brew OpenSSL is correctly linked by running + + brew link openssl --force + +Rerunning "openssl version" should now return the correct version. + +### Building `casinocoind` + +1. Clone the github tree to get the source code and go into the directory. + + git clone git@github.com:transcoder/CasinoCoin.git casinocoin + cd casinocoin + +2. Modify source in order to pick up the `openssl` library. + + Edit `makefile.osx` to account for library location differences. There's a + diff in `contrib/homebrew/makefile.osx.patch` that shows what you need to + change, or you can just patch by doing + + patch -p1 < contrib/homebrew/makefile.osx.patch + +3. Build casinocoind: + + cd src + make -f makefile.osx + +4. It is a good idea to build and run the unit tests, too: + + make -f makefile.osx test + +Creating a release build +------------------------ + +A casinocoind binary is not included in the CasinoCoin-Qt.app bundle. You can ignore +this section if you are building `casinocoind` for your own use. + +If you are building `litecond` for others, your build machine should be set up +as follows for maximum compatibility: + +All dependencies should be compiled with these flags: + + -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + +For MacPorts, that means editing your macports.conf and setting +`macosx_deployment_target` and `build_arch`: + + macosx_deployment_target=10.5 + build_arch=i386 + +... and then uninstalling and re-installing, or simply rebuilding, all ports. + +As of December 2012, the `boost` port does not obey `macosx_deployment_target`. +Download `http://gavinandresen-bitcoin.s3.amazonaws.com/boost_macports_fix.zip` +for a fix. Some ports also seem to obey either `build_arch` or +`macosx_deployment_target`, but not both at the same time. For example, building +on an OS X 10.6 64-bit machine fails. Official release builds of CasinoCoin-Qt are +compiled on an OS X 10.6 32-bit machine to workaround that problem. + +Once dependencies are compiled, creating `CasinoCoin-Qt.app` is easy: + + make -f Makefile.osx RELEASE=1 + +Running +------- + +It's now available at `./casinocoind`, provided that you are still in the `src` +directory. We have to first create the RPC configuration file, though. + +Run `./casinocoind` to get the filename where it should be put, or just try these +commands: + + echo -e "rpcuser=casinocoinrpc\nrpcpassword=$(xxd -l 16 -p /dev/urandom)" > "/Users/${USER}/Library/Application Support/CasinoCoin/casinocoin.conf" + chmod 600 "/Users/${USER}/Library/Application Support/CasinoCoin/casinocoin.conf" + +When next you run it, it will start downloading the blockchain, but it won't +output anything while it's doing this. This process may take several hours. + +Other commands: + + ./casinocoind --help # for a list of command-line options. + ./casinocoind -daemon # to start the casinocoin daemon. + ./casinocoind help # When the daemon is running, to get a list of RPC commands diff --git a/doc/build-unix.md b/doc/build-unix.md new file mode 100644 index 0000000..98dade3 --- /dev/null +++ b/doc/build-unix.md @@ -0,0 +1,154 @@ +Copyright (c) 2009-2013 Bitcoin Developers + +Distributed under the MIT/X11 software license, see the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://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. + +UNIX BUILD NOTES +==================== + +To Build +--------------------- + + cd src/ + make -f makefile.unix # Headless casinocoin + +See readme-qt.rst for instructions on building CasinoCoin-Qt, the graphical user interface. + +Dependencies +--------------------- + + Library Purpose Description + ------- ------- ----------- + libssl SSL Support Secure communications + libdb4.8 Berkeley DB Blockchain & wallet storage + libboost Boost C++ Library + miniupnpc UPnP Support Optional firewall-jumping support + +[miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here]( +http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and +turned off by default. Set USE_UPNP to a different value to control this: + + USE_UPNP= No UPnP support miniupnp not required + USE_UPNP=0 (the default) UPnP support turned off by default at runtime + USE_UPNP=1 UPnP support turned on by default at runtime + +IPv6 support may be disabled by setting: + + USE_IPV6=0 Disable IPv6 support + +Licenses of statically linked libraries: + Berkeley DB New BSD license with additional requirement that linked + software must be free open source + Boost MIT-like license + miniupnpc New (3-clause) BSD license + +- Versions used in this release: +- GCC 4.3.3 +- OpenSSL 1.0.1c +- Berkeley DB 4.8.30.NC +- Boost 1.37 +- miniupnpc 1.6 + +Dependency Build Instructions: Ubuntu & Debian +---------------------------------------------- +Build requirements: + + sudo apt-get install build-essential + sudo apt-get install libssl-dev + +for Ubuntu 12.04: + + sudo apt-get install libboost-all-dev + + db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). + + Ubuntu precise has packages for libdb5.1-dev and libdb5.1++-dev, + but using these will break binary wallet compatibility, and is not recommended. + +for other Ubuntu & Debian: + + sudo apt-get install libdb4.8-dev + sudo apt-get install libdb4.8++-dev + sudo apt-get install libboost1.37-dev + (If using Boost 1.37, append -mt to the boost libraries in the makefile) + +Optional: + + sudo apt-get install libminiupnpc-dev (see USE_UPNP compile flag) + + +Notes +----- +The release is built with GCC and then "strip bitcoind" to strip the debug +symbols, which reduces the executable size by about 90%. + + +miniupnpc +--------- + tar -xzvf miniupnpc-1.6.tar.gz + cd miniupnpc-1.6 + make + sudo su + make install + + +Berkeley DB +----------- +You need Berkeley DB 4.8. If you have to build Berkeley DB yourself: + + ../dist/configure --enable-cxx + make + + +Boost +----- +If you need to build Boost yourself: + + sudo su + ./bootstrap.sh + ./bjam install + + +Security +-------- +To help make your casinocoin installation more secure by making certain attacks impossible to +exploit even if a vulnerability is found, you can take the following measures: + +* Position Independent Executable + Build position independent code to take advantage of Address Space Layout Randomization + offered by some kernels. An attacker who is able to cause execution of code at an arbitrary + memory location is thwarted if he doesn't know where anything useful is located. + The stack and heap are randomly located by default but this allows the code section to be + randomly located as well. + + On an Amd64 processor where a library was not compiled with -fPIC, this will cause an error + such as: "relocation R_X86_64_32 against `......' can not be used when making a shared object;" + + To build with PIE, use: + make -f makefile.unix ... -e PIE=1 + + To test that you have built PIE executable, install scanelf, part of paxutils, and use: + + scanelf -e ./casinocoin + + The output should contain: + TYPE + ET_DYN + +* Non-executable Stack + If the stack is executable then trivial stack based buffer overflow exploits are possible if + vulnerable buffers are found. By default, bitcoin should be built with a non-executable stack + but if one of the libraries it uses asks for an executable stack or someone makes a mistake + and uses a compiler extension which requires an executable stack, it will silently build an + executable without the non-executable stack protection. + + To verify that the stack is non-executable after compiling use: + `scanelf -e ./casinocoin` + + the output should contain: + STK/REL/PTL + RW- R-- RW- + + The STK RW- means that the stack is readable and writeable but not executable. diff --git a/doc/coding.md b/doc/coding.md new file mode 100644 index 0000000..3581d7d --- /dev/null +++ b/doc/coding.md @@ -0,0 +1,94 @@ +Coding +==================== + +Please be consistent with the existing coding style. + +Block style: + + bool Function(char* psz, int n) + { + // Comment summarising what this section of code does + for (int i = 0; i < n; i++) + { + // When something fails, return early + if (!Something()) + return false; + ... + } + + // Success return is usually at the end + return true; + } + +- ANSI/Allman block style +- 4 space indenting, no tabs +- No extra spaces inside parenthesis; please don't do ( this ) +- No space after function names, one space after if, for and while + +Variable names begin with the type in lowercase, like nSomeVariable. +Please don't put the first word of the variable name in lowercase like +someVariable. + +Common types: + + n integer number: short, unsigned short, int, unsigned int, int64, uint64, sometimes char if used as a number + d double, float + f flag + hash uint256 + p pointer or array, one p for each level of indirection + psz pointer to null terminated string + str string object + v vector or similar list objects + map map or multimap + set set or multiset + bn CBigNum + +------------------------- +Locking/mutex usage notes + +The code is multi-threaded, and uses mutexes and the +LOCK/TRY_LOCK macros to protect data structures. + +Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main +and then cs_wallet, while thread 2 locks them in the opposite order: +result, deadlock as each waits for the other to release its lock) are +a problem. Compile with -DDEBUG_LOCKORDER to get lock order +inconsistencies reported in the debug.log file. + +Re-architecting the core code so there are better-defined interfaces +between the various components is a goal, with any necessary locking +done by the components (e.g. see the self-contained CKeyStore class +and its cs_KeyStore lock for example). + +------- +Threads + +- StartNode : Starts other threads. + +- ThreadGetMyExternalIP : Determines outside-the-firewall IP address, sends addr message to connected peers when it determines it. + +- ThreadSocketHandler : Sends/Receives data from peers on port 8333. + +- ThreadMessageHandler : Higher-level message handling (sending and receiving). + +- ThreadOpenConnections : Initiates new connections to peers. + +- ThreadTopUpKeyPool : replenishes the keystore's keypool. + +- ThreadCleanWalletPassphrase : re-locks an encrypted wallet after user has unlocked it for a period of time. + +- SendingDialogStartTransfer : used by pay-via-ip-address code (obsolete) + +- ThreadDelayedRepaint : repaint the gui + +- ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used in 500ms. + +- ThreadRPCServer : Remote procedure call handler, listens on port 8332 for connections and services them. + +- ThreadBitcoinMiner : Generates bitcoins + +- ThreadMapPort : Universal plug-and-play startup/shutdown + +- Shutdown : Does an orderly shutdown of everything + +- ExitTimeout : Windows-only, sleeps 5 seconds then exits application diff --git a/doc/files.txt b/doc/files.txt new file mode 100644 index 0000000..5d4cdab --- /dev/null +++ b/doc/files.txt @@ -0,0 +1,19 @@ +Used in 0.8.0: +* wallet.dat: personal wallet (BDB) with keys and transactions +* peers.dat: peer IP address database (custom format); since 0.7.0 +* blocks/blk000??.dat: block data (custom, 128 MiB per file); since 0.8.0 +* blocks/rev000??.dat; block undo data (custom); since 0.8.0 (format changed since pre-0.8) +* blocks/index/*; block index (LevelDB); since 0.8.0 +* chainstate/*; block chain state database (LevelDB); since 0.8.0 +* database/*: BDB database environment; only used for wallet since 0.8.0 + +Only used in pre-0.8.0: +* blktree/*; block chain index (LevelDB); since pre-0.8, replaced by blocks/index/* in 0.8.0 +* coins/*; unspent transaction output database (LevelDB); since pre-0.8, replaced by chainstate/* in 0.8.0 + +Only used before 0.8.0: +* blkindex.dat: block chain index database (BDB); replaced by {chainstate/*,blocks/index/*,blocks/rev000??.dat} in 0.8.0 +* blk000?.dat: block data (custom, 2 GiB per file); replaced by blocks/blk000??.dat in 0.8.0 + +Only used before 0.7.0: +* addr.dat: peer IP address database (BDB); replaced by peers.dat in 0.7.0 diff --git a/doc/multiwallet-qt.md b/doc/multiwallet-qt.md new file mode 100644 index 0000000..8d69555 --- /dev/null +++ b/doc/multiwallet-qt.md @@ -0,0 +1,52 @@ +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. + +Three new classes have been implemented in three 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, three 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 *WalletStack*, also inheriting from QStackedWidget, has been written to handle switching focus between +different loaded wallets. In its current implementation, as a QStackedWidget, only one wallet can be viewed at a time - +but this can be changed later. + +A third class called *WalletFrame* inheriting from QFrame has been written as a container for embedding all wallet-related +controls into BitcoinGUI. At present it just contains a WalletStack instance and does little more than passing on messages +from BitcoinGUI to the WalletStack, which in turn passes them to the individual WalletViews. 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/readme-qt.rst b/doc/readme-qt.rst index 4370335..ccb407e 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -1,5 +1,5 @@ CasinoCoin-Qt: Qt4 GUI for CasinoCoin -================================ +=============================== Build instructions =================== @@ -8,13 +8,31 @@ Debian ------- First, make sure that the required packages for Qt4 development of your -distribution are installed, for Debian and Ubuntu these are: +distribution are installed, these are + +:: + +for Debian and Ubuntu <= 11.10 : :: apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ - libssl-dev libdb4.8++-dev + libssl-dev libdb4.8++-dev libminiupnpc-dev + +for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): + +:: + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb++-dev libminiupnpc-dev + +For Qt 5 you need the following, otherwise you get an error with lrelease when running qmake: + +:: + + apt-get install qt5-qmake libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev-tools then execute the following: @@ -27,45 +45,38 @@ Alternatively, install `Qt Creator`_ and open the `casinocoin-qt.pro` file. An executable named `casinocoin-qt` will be built. -.. _`Qt Creator`: http://qt.nokia.com/downloads/ - -Windows --------- - -Windows build instructions: - -- Download the `Qt Windows SDK`_ and install it. You don't need the Symbian stuff, just the desktop Qt. - -- Download and extract the `dependencies archive`_ [#]_, or compile openssl, boost and dbcxx yourself. - -- Copy the contents of the folder "deps" to "X:\\QtSDK\\mingw", replace X:\\ with the location where you installed the Qt SDK. Make sure that the contents of "deps\\include" end up in the current "include" directory. - -- Open the bitcoin-qt.pro file in Qt Creator and build as normal (ctrl-B) - -.. _`Qt Windows SDK`: http://qt.nokia.com/downloads/sdk-windows-cpp -.. _`dependencies archive`: https://download.visucore.com/bitcoin/qtgui_deps_1.zip -.. [#] PGP signature: https://download.visucore.com/bitcoin/qtgui_deps_1.zip.sig (signed with RSA key ID `610945D0`_) -.. _`610945D0`: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x610945D0 - +.. _`Qt Creator`: http://qt-project.org/downloads/ Mac OS X -------- - Download and install the `Qt Mac OS X SDK`_. It is recommended to also install Apple's Xcode with UNIX tools. -- Download and install `MacPorts`_. +- Download and install either `MacPorts`_ or `HomeBrew`_. -- Execute the following commands in a terminal to get the dependencies: +- Execute the following commands in a terminal to get the dependencies using MacPorts: :: sudo port selfupdate sudo port install boost db48 miniupnpc -- Open the bitcoin-qt.pro file in Qt Creator and build as normal (cmd-B) +- Execute the following commands in a terminal to get the dependencies using HomeBrew: -.. _`Qt Mac OS X SDK`: http://qt.nokia.com/downloads/sdk-mac-os-cpp +:: + + brew update + brew install boost miniupnpc openssl berkeley-db4 + +- If using HomeBrew, edit `casinocoin-qt.pro` to account for library location differences. There's a diff in `contrib/homebrew/bitcoin-qt-pro.patch` that shows what you need to change, or you can just patch by doing + + patch -p1 < contrib/homebrew/bitcoin.qt.pro.patch + +- Open the casinocoin-qt.pro file in Qt Creator and build as normal (cmd-B) + +.. _`Qt Mac OS X SDK`: http://qt-project.org/downloads/ .. _`MacPorts`: http://www.macports.org/install.php +.. _`HomeBrew`: http://mxcl.github.io/homebrew/ Build configuration options @@ -108,8 +119,8 @@ FreeDesktop notification interface through DBUS using the following qmake option Generation of QR codes ----------------------- -libqrencode may be used to generate QRCode images for payment requests. -It can be downloaded from http://fukuchi.org/works/qrencode/index.html.en, or installed via your package manager. Pass the USE_QRCODE +libqrencode may be used to generate QRCode images for payment requests. +It can be downloaded from http://fukuchi.org/works/qrencode/index.html.en, or installed via your package manager. Pass the USE_QRCODE flag to qmake to control this: +--------------+--------------------------------------------------------------------------+ diff --git a/doc/release-notes.md b/doc/release-notes.md new file mode 100644 index 0000000..51b0f83 --- /dev/null +++ b/doc/release-notes.md @@ -0,0 +1,100 @@ +1.1.0.0 changes +============= + +Implemented the Kimoto Gravity Well algorithm (courtesy of @kimoto of Megacoin) for use in the difficulty adjustment in order to combat pool hopping. + +Incorporated the following Litecoin changes below. + + +0.8.6.2 changes +============= + +- Windows only: Fixes issue where network connectivity can fail. + +- Cleanup of SSE2 scrypt detection. + +- Minor fixes: + - s/Bitcoin/Litecoin/ in the Coin Control example + - Fix custom build on MacOS X 10.9 + - Fix QT5 custom build + - Update Debian build instructions + - Update Homebrew build + +0.8.6.1 changes +============= + +- Coin Control - experts only GUI selection of inputs before you send a transaction + +- Disable Wallet - reduces memory requirements, helpful for miner or relay nodes + +- 20x reduction in default mintxfee. + +- Up to 50% faster PoW validation, faster sync and reindexing. + +- Peers older than protocol version 70002 are disconnected. 0.8.3.7 is the oldest compatible client. + +- Internal miner added back to Litecoin. setgenerate now works, although it is generally a bad idea as it is significantly slower than external CPU miners. + +- New RPC commands: getbestblockhash and verifychain + +- Improve fairness of the high priority transaction space per block + +- OSX block chain database corruption fixes + - Update leveldb to 1.13 + - Use fcntl with `F_FULLSYNC` instead of fsync on OSX + - Use native Darwin memory barriers + - Replace use of mmap in leveldb for improved reliability (only on OSX) + +- Fix nodes forwarding transactions with empty vins and getting banned + +- Network code performance and robustness improvements + +- Additional debug.log logging for diagnosis of network problems, log timestamps by default + +- Fix rare GUI crash on send + +0.8.5.1 changes +=============== + +Workaround negative version numbers serialization bug. + +Fix out-of-bounds check (Litecoin currently does not use this codepath, but we apply this +patch just to match Bitcoin 0.8.5.) + +0.8.4.1 changes +=============== + +CVE-2013-5700 Bloom: filter crash issue - Litecoin 0.8.3.7 disabled bloom by default so was +unaffected by this issue, but we include their patches anyway just in case folks want to +enable bloomfilter=1. + +CVE-2013-4165: RPC password timing guess vulnerability + +CVE-2013-4627: Better fix for the fill-memory-with-orphaned-tx attack + +Fix multi-block reorg transaction resurrection. + +Fix non-standard disconnected transactions causing mempool orphans. This bug could cause +nodes running with the -debug flag to crash, although it was lot less likely on Litecoin +as we disabled IsDust() in 0.8.3.x. + +Mac OSX: use 'FD_FULLSYNC' with LevelDB, which will (hopefully!) prevent the database +corruption issues have experienced on OSX. + +Add height parameter to getnetworkhashps. + +Fix Norwegian and Swedish translations. + +Minor efficiency improvement in block peer request handling. + + +0.8.3.7 changes +=============== + +Fix CVE-2013-4627 denial of service, a memory exhaustion attack that could crash low-memory nodes. + +Fix a regression that caused excessive writing of the peers.dat file. + +Add option for bloom filtering. + +Fix Hebrew translation. diff --git a/doc/release-process.md b/doc/release-process.md new file mode 100644 index 0000000..ffd2457 --- /dev/null +++ b/doc/release-process.md @@ -0,0 +1,161 @@ +Release Process +==================== + +* * * + +###update (commit) version in sources + + + casinocoin-qt.pro + contrib/verifysfbinaries/verify.sh + doc/README* + share/setup.nsi + src/clientversion.h (change CLIENT_VERSION_IS_RELEASE to true) + +###tag version in git + + git tag -a v0.8.0 + +###write release notes. git shortlog helps a lot, for example: + + git shortlog --no-merges v0.7.2..v0.8.0 + +* * * + +##perform gitian builds + + From a directory containing the casinocoin source, gitian-builder and gitian.sigs + + export SIGNER=(your gitian key, ie bluematt, sipa, etc) + export VERSION=0.8.0 + cd ./gitian-builder + + Fetch and build inputs: (first time, or when dependency versions change) + + mkdir -p inputs; cd inputs/ + wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz + wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz' + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' + wget 'http://zlib.net/zlib-1.2.6.tar.gz' + wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz' + wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2' + wget 'http://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2' + wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz' + cd .. + ./bin/gbuild ../casinocoin/contrib/gitian-descriptors/boost-win32.yml + mv build/out/boost-win32-1.50.0-gitian2.zip inputs/ + ./bin/gbuild ../casinocoin/contrib/gitian-descriptors/qt-win32.yml + mv build/out/qt-win32-4.8.3-gitian-r1.zip inputs/ + ./bin/gbuild ../casinocoin/contrib/gitian-descriptors/deps-win32.yml + mv build/out/casinocoin-deps-0.0.5.zip inputs/ + + Build casinocoind and casinocoin-qt on Linux32, Linux64, and Win32: + + ./bin/gbuild --commit casinocoin=v${VERSION} ../casinocoin/contrib/gitian-descriptors/gitian.yml + ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../casinocoin/contrib/gitian-descriptors/gitian.yml + pushd build/out + zip -r casinocoin-${VERSION}-linux-gitian.zip * + mv casinocoin-${VERSION}-linux-gitian.zip ../../ + popd + ./bin/gbuild --commit casinocoin=v${VERSION} ../casinocoin/contrib/gitian-descriptors/gitian-win32.yml + ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../casinocoin/contrib/gitian-descriptors/gitian-win32.yml + pushd build/out + zip -r casinocoin-${VERSION}-win32-gitian.zip * + mv casinocoin-${VERSION}-win32-gitian.zip ../../ + popd + + Build output expected: + + 1. linux 32-bit and 64-bit binaries + source (casinocoin-${VERSION}-linux-gitian.zip) + 2. windows 32-bit binary, installer + source (casinocoin-${VERSION}-win32-gitian.zip) + 3. Gitian signatures (in gitian.sigs/${VERSION}[-win32]/(your gitian key)/ + +repackage gitian builds for release as stand-alone zip/tar/installer exe + +**Linux .tar.gz:** + + unzip casinocoin-${VERSION}-linux-gitian.zip -d casinocoin-${VERSION}-linux + tar czvf casinocoin-${VERSION}-linux.tar.gz casinocoin-${VERSION}-linux + rm -rf casinocoin-${VERSION}-linux + +**Windows .zip and setup.exe:** + + unzip casinocoin-${VERSION}-win32-gitian.zip -d casinocoin-${VERSION}-win32 + mv casinocoin-${VERSION}-win32/casinocoin-*-setup.exe . + zip -r casinocoin-${VERSION}-win32.zip bitcoin-${VERSION}-win32 + rm -rf casinocoin-${VERSION}-win32 + +**Perform Mac build:** + + OSX binaries are created by Gavin Andresen on a 32-bit, OSX 10.6 machine. + + qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 casinocoin-qt.pro + make + export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files + T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) + python2.7 share/qt/clean_mac_info_plist.py + python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist + + Build output expected: Bitcoin-Qt.dmg + +###Next steps: + +* Code-sign Windows -setup.exe (in a Windows virtual machine) and + OSX Bitcoin-Qt.app (Note: only Gavin has the code-signing keys currently) + +* upload builds to SourceForge + +* create SHA256SUMS for builds, and PGP-sign it + +* update casinocoin.org version + make sure all OS download links go to the right versions + +* update forum version + +* update wiki download links + +* update wiki changelog: [https://en.casinocoin.it/wiki/Changelog](https://en.bitcoin.it/wiki/Changelog) + +Commit your signature to gitian.sigs: + + pushd gitian.sigs + git add ${VERSION}/${SIGNER} + git add ${VERSION}-win32/${SIGNER} + git commit -a + git push # Assuming you can push to the gitian.sigs tree + popd + +------------------------------------------------------------------------- + +### After 3 or more people have gitian-built, repackage gitian-signed zips: + +From a directory containing casinocoin source, gitian.sigs and gitian zips + + export VERSION=0.5.1 + mkdir casinocoin-${VERSION}-linux-gitian + pushd casinocoin-${VERSION}-linux-gitian + unzip ../casinocoin-${VERSION}-linux-gitian.zip + mkdir gitian + cp ../casinocoin/contrib/gitian-downloader/*.pgp ./gitian/ + for signer in $(ls ../gitian.sigs/${VERSION}/); do + cp ../gitian.sigs/${VERSION}/${signer}/casinocoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}/${signer}/casinocoin-build.assert.sig ./gitian/${signer}-build.assert.sig + done + zip -r casinocoin-${VERSION}-linux-gitian.zip * + cp casinocoin-${VERSION}-linux-gitian.zip ../ + popd + mkdir casinocoin-${VERSION}-win32-gitian + pushd casinocoin-${VERSION}-win32-gitian + unzip ../casinocoin-${VERSION}-win32-gitian.zip + mkdir gitian + cp ../casinocoin/contrib/gitian-downloader/*.pgp ./gitian/ + for signer in $(ls ../gitian.sigs/${VERSION}-win32/); do + cp ../gitian.sigs/${VERSION}-win32/${signer}/casinocoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}-win32/${signer}/casinocoin-build.assert.sig ./gitian/${signer}-build.assert.sig + done + zip -r casinocoin-${VERSION}-win32-gitian.zip * + cp casinocoin-${VERSION}-win32-gitian.zip ../ + popd + +- Upload gitian zips to SourceForge +- Celebrate diff --git a/doc/translation_process.md b/doc/translation_process.md index c483020..1724e95 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -34,10 +34,12 @@ This directory contains all translations. Filenames must adhere to this format: source for all other translations. Whenever a string in the code is changed this file must be updated to reflect those changes. This can be accomplished by running `lupdate` (included in the Qt SDK). Also, a custom script is used -to extract strings from the non-Qt parts: +to extract strings from the non-Qt parts. This script makes use of `gettext`, +so make sure that utility is installed (ie, `apt-get install gettext` on +Ubuntu/Debian): python share/qt/extract_strings_qt.py - lupdate bitcoin-qt.pro -no-obsolete -locations none -ts src/qt/locale/bitcoin_en.ts + lupdate bitcoin-qt.pro -no-obsolete -locations relative -ts src/qt/locale/bitcoin_en.ts ##### Handling of plurals in the source file diff --git a/doc/unit-tests.md b/doc/unit-tests.md new file mode 100644 index 0000000..78bdc73 --- /dev/null +++ b/doc/unit-tests.md @@ -0,0 +1,35 @@ +Compiling/running casinocoind unit tests +------------------------------------ + +casinocoind unit tests are in the `src/test/` directory; they +use the Boost::Test unit-testing framework. + +To compile and run the tests: + + cd src + make -f makefile.unix test_casinocoin # Replace makefile.unix if you're not on unix + ./test_casinocoin # Runs the unit tests + +If all tests succeed the last line of output will be: +`*** No errors detected` + +To add more 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 (the makefiles are +set up to add test/*.cpp to test_casinocoin automatically). + + +Compiling/running CasinoCoin-Qt unit tests +--------------------------------------- + +Bitcoin-Qt unit tests are in the src/qt/test/ directory; they +use the Qt unit-testing framework. + +To compile and run the tests: + + qmake bitcoin-qt.pro BITCOIN_QT_TEST=1 + make + ./casinocoin-qt_test + +To add more tests, add them to the `src/qt/test/` directory, +the `src/qt/test/test_main.cpp` file, and bitcoin-qt.pro. diff --git a/share/certs/BitcoinFoundation_Apple_Cert.pem b/share/certs/BitcoinFoundation_Apple_Cert.pem new file mode 100644 index 0000000..beb0d70 --- /dev/null +++ b/share/certs/BitcoinFoundation_Apple_Cert.pem @@ -0,0 +1,37 @@ +Bag Attributes + friendlyName: Developer ID Application: BITCOIN FOUNDATION, INC., THE + localKeyID: 6B 9C 6C A8 A5 73 70 70 E2 57 A3 49 D8 62 FB 97 C7 A5 5D 5E +subject=/UID=PBV4GLS9J4/CN=Developer ID Application: BITCOIN FOUNDATION, INC., THE/OU=PBV4GLS9J4/O=BITCOIN FOUNDATION, INC., THE/C=US +issuer=/CN=Developer ID Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US +-----BEGIN CERTIFICATE----- +MIIFhzCCBG+gAwIBAgIIJ0r1rumyfZAwDQYJKoZIhvcNAQELBQAweTEtMCsGA1UE +AwwkRGV2ZWxvcGVyIElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQL +DB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUg +SW5jLjELMAkGA1UEBhMCVVMwHhcNMTMwMTEwMjIzOTAxWhcNMTgwMTExMjIzOTAx +WjCBqDEaMBgGCgmSJomT8ixkAQEMClBCVjRHTFM5SjQxQDA+BgNVBAMMN0RldmVs +b3BlciBJRCBBcHBsaWNhdGlvbjogQklUQ09JTiBGT1VOREFUSU9OLCBJTkMuLCBU +SEUxEzARBgNVBAsMClBCVjRHTFM5SjQxJjAkBgNVBAoMHUJJVENPSU4gRk9VTkRB +VElPTiwgSU5DLiwgVEhFMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALTd5zURuZVoJviusr119aktXksenb9IN9vq6kBbq38vxEk7 +9wkKMES2XfBRh0HxcEizGzhMNy5OCXuTLMaNMihYdfwYSoBoR2foEU+6kjPUnyJ4 +dQBFLJZJr5/QeQmALmYHEgZ6lwXFD2lU8t92340zeJ4y5LZw5pcEHtH9IummYDut +OGCkCGXDcjL+5nHhNScJiXHhswM+62o6XXsQiP6EWbM1CsgrGTNLtaa0U/UvVDwE +79YKklSC5Bog2LD0jBcTuveI66mFzqu++L9X9u+ZArtebwCl7BPNQ+uboYy5uV2d +zf8lpNNZLfXCFjoLe9bLICKfZ7ub9V5aC8+GhckCAwEAAaOCAeEwggHdMD4GCCsG +AQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuYXBwbGUuY29tL29j +c3AtZGV2aWQwMTAdBgNVHQ4EFgQUa5xsqKVzcHDiV6NJ2GL7l8elXV4wDAYDVR0T +AQH/BAIwADAfBgNVHSMEGDAWgBRXF+2iz9x8mKEQ4Py+hy0s8uMXVDCCAQ4GA1Ud +IASCAQUwggEBMIH+BgkqhkiG92NkBQEwgfAwKAYIKwYBBQUHAgEWHGh0dHA6Ly93 +d3cuYXBwbGUuY29tL2FwcGxlY2EwgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ug +b24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRh +bmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNv +bmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmlj +YXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wDgYDVR0PAQH/BAQDAgeAMBYGA1Ud +JQEB/wQMMAoGCCsGAQUFBwMDMBMGCiqGSIb3Y2QGAQ0BAf8EAgUAMA0GCSqGSIb3 +DQEBCwUAA4IBAQAfJ0BjID/1dS2aEeVyhAzPzCBjG8vm0gDf+/qfwRn3+yWeL9vS +nMdbilwM48IyQWTagjGGcojbsAd/vE4N7NhQyHInoCllNoeor1I5xx+blTaGRBK+ +dDhJbbdlGCjsLnH/BczGZi5fyEJds9lUIrp1hJidRcUKO76qb/9gc6qNZpl1vH5k +lDUuJYt7YhAs+L6rTXDyqcK9maeQr0gaOPsRRAQLLwiQCorPeMTUNsbVMdMwZYJs +R+PxiAnk+nyi7rfiFvPoASAYUuI6OzYL/Fa6QU4/gYyPgic944QYVkaQBnc0vEP1 +nXq6LGKwgVGcqJnkr/E2kui5gJoV5C3qll3e +-----END CERTIFICATE----- diff --git a/share/certs/BitcoinFoundation_Comodo_Cert.pem b/share/certs/BitcoinFoundation_Comodo_Cert.pem new file mode 100644 index 0000000..dc752d4 --- /dev/null +++ b/share/certs/BitcoinFoundation_Comodo_Cert.pem @@ -0,0 +1,37 @@ +Bag Attributes + friendlyName: The Bitcoin Foundation, Inc.'s COMODO CA Limited ID + localKeyID: 8C 94 64 E3 B5 B0 41 89 5B 89 B0 57 CC 74 B9 44 E5 B2 92 66 +subject=/C=US/postalCode=98104-1444/ST=WA/L=Seattle/street=Suite 300/street=71 Columbia St/O=The Bitcoin Foundation, Inc./CN=The Bitcoin Foundation, Inc. +issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2 +-----BEGIN CERTIFICATE----- +MIIFeDCCBGCgAwIBAgIRAJVYMd+waOER7lUqtiz3M2IwDQYJKoZIhvcNAQEFBQAw +ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxITAfBgNV +BAMTGENPTU9ETyBDb2RlIFNpZ25pbmcgQ0EgMjAeFw0xMzAxMTYwMDAwMDBaFw0x +NDAxMTYyMzU5NTlaMIG8MQswCQYDVQQGEwJVUzETMBEGA1UEEQwKOTgxMDQtMTQ0 +NDELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEjAQBgNVBAkMCVN1aXRl +IDMwMDEXMBUGA1UECQwONzEgQ29sdW1iaWEgU3QxJTAjBgNVBAoMHFRoZSBCaXRj +b2luIEZvdW5kYXRpb24sIEluYy4xJTAjBgNVBAMMHFRoZSBCaXRjb2luIEZvdW5k +YXRpb24sIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChUwLD +u/hu5aFZ/n11B27awONaaDrmHm0pamiWHb01yL4JmTBtaLCrSftF8RhCscQ8jpI0 +UG1Cchmay0e3zH5o5XRs0H9C3x+SM5ozms0TWDmAYiB8aQEghsGovDk0D2nyTQeK +Q0xqyCh0m8ZPOnMnYrakHEmF6WvhLdJvI6Od4KIwbKxgN17cPFIfLVsZ7GrzmmbU +Gdi4wSQCHy5rxzvBxho8Qq/SfBl93uOMUrqOHjOUAPhNuTJG3t/MdhU8Zp24s29M +abHtYkT9W86hMjIiI8RTAR+WHKVglx9SB0cjDabXN8SZ3gME0+H++LyzlySHT8sI +ykepojZ7UBRgp9w3AgMBAAGjggGzMIIBrzAfBgNVHSMEGDAWgBQexbEsfYfaAmh8 +JbwMB4Q/ts/e8TAdBgNVHQ4EFgQUfPf+ZyDWl/4LH0Y5BuJTelkRd/EwDgYDVR0P +AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJ +YIZIAYb4QgEBBAQDAgQQMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQMCMCswKQYI +KwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMEEGA1UdHwQ6 +MDgwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWdu +aW5nQ0EyLmNybDByBggrBgEFBQcBAQRmMGQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9j +cnQuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWduaW5nQ0EyLmNydDAkBggrBgEF +BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMCgGA1UdEQQhMB+BHWxpbmRz +YXlAYml0Y29pbmZvdW5kYXRpb24ub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAqibjo +D4HG5XSIIMCmYE5RgQBSEAJfI+EZERk1G9F83ZUWr0yNRZCw4O+RaM7xQhvJhEoD +G2kpk/q2bNOc71/VyZ6SrE1JRVUON41/Flhz4M6cP0BclTicXvh+efVwqZhIz+ws +UxF2hvC/1Xx6rqI7NYAlOYXk2MSUq3HREo+gWUPKM8em4MZZV/7XCH4QbsfxOl1J +xS6EOQmV8hfUN4KRXI5WfGUmedBxq7dM0RSJOSQl8fq2f+JjRLfjQwQucy7LDY+y +pRTsL2TdQV/DuDuI3s0NHRGznQNddoX5jqpXhSQFAAdgrhN1gGkWaaTPzr9IF2TG +qgr6PEp9tIYC+MbM +-----END CERTIFICATE----- diff --git a/share/certs/PrivateKeyNotes.md b/share/certs/PrivateKeyNotes.md new file mode 100644 index 0000000..da299d1 --- /dev/null +++ b/share/certs/PrivateKeyNotes.md @@ -0,0 +1,46 @@ +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 +signing requests. + +For OSX, the private key was generated by Keychain.app on Gavin's main work machine. +The key and certificate is in a separate, passphrase-protected keychain file that is +unlocked to sign the Bitcoin-Qt.app bundle. + +For Windows, the private key was generated by Firefox running on Gavin's main work machine. +The key and certificate were exported into a separate, passphrase-protected PKCS#12 file, and +then deleted from Firefox's keystore. The exported file is used to sign the Windows setup.exe. + +Threat analysis +-- + +Gavin is a single point of failure. He could be coerced to divulge the secret signing keys, +allowing somebody to distribute a Bitcoin-Qt.app or bitcoin-qt-setup.exe with a valid +signature but containing a malicious binary. + +Or the machine Gavin uses to sign the binaries could be compromised, either remotely or +by breaking in to his office, allowing the attacker to get the private key files and then +install a keylogger to get the passphrase that protects them. + +Threat Mitigation +-- + +"Air gapping" the machine used to do the signing will not work, because the signing +process needs to access a timestamp server over the network. And it would not +prevent the "rubber hose cryptography" threat (coercing Gavin to sign a bad binary +or divulge the private keys). + +Windows binaries are reproducibly 'gitian-built', and the setup.exe file created +by the NSIS installer system is a 7zip archive, so you could check to make sure +that the bitcoin-qt.exe file inside the installer had not been tampered with. +However, an attacker could modify the installer's code, so when the setup.exe +was run it compromised users' systems. A volunteer to write an auditing tool +that checks the setup.exe for tampering, and checks the files in it against +the list of gitian signatures, is needed. + +The long-term solution is something like the 'gitian downloader' system, which +uses signatures from multiple developers to determine whether or not a binary +should be trusted. However, that just pushes the problem to "how will +non-technical users securely get the gitian downloader code to start?" diff --git a/share/pixmaps/bitcoin-bc.ico b/share/pixmaps/bitcoin-bc.ico index 476045c6ec203fd6954baf0c3b46afada06a2b7f..83a01ea4c885ba6aebbc30fd86bfd8e42d0db9ad 100644 GIT binary patch literal 15086 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 P`B=VsW5d0k@$CNr{MG0+ literal 15086 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 diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico index 8b12f825727a1e04e93ce39af9cc79095a8af1e9..37533703f76aff466fc74158119db10474279fb0 100644 GIT binary patch literal 89957 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%0D%_iEz7^_~hg4?7T(nOcS4t5^LRG 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 c None", +", c #EEEEEE", +"< c #5D5D5D", +"1 c #595959", +"2 c #404040", +"3 c #4B4B4B", +"4 c None", +"5 c #313131", +"6 c #404040", +"7 c #707070", +"8 c None", +"9 c None", +"0 c None", +"q c #535353", +"w c #404040", +"e c #757575", +"r c #525252", +"t c #5A5A5A", +"y c #686868", +"u c #4B4B4B", +"i c #404040", +"p c #979797", +"a c #616161", +"s c None", +"d c #5A5A5A", +"f c #B9B9B9", +"g c #404040", +"h c #DBDBDB", +"j c #565656", +"k c None", +"l c None", +"z c #FDFDFD", +"x c #5A5A5A", +"c c #5A5A5A", +"v c #4B4B4B", +"b c #404040", +"n c #1E1E1E", +"m c #646464", +"M c #404040", +"N c #595959", +"B c #4F4F4F", +"V c #626262", +"C c #525252", +"Z c #4F4F4F", +"A c None", +"S c #848484", +"D c None", +"F c #4F4F4F", +"G c #525252", +"H c #A6A6A6", +"J c #595959", +"K c #4B4B4B", +"L c None", +"P c None", +"I c #C8C8C8", +"U c #707070", +"Y c #646464", +"T c None", +"R c #525252", +"E c #EAEAEA", +"W c #4B4B4B", +"Q c #707070", +"! c None", +"~ c None", +"^ c #595959", +"/ c None", +"( c None", +") c #2D2D2D", +"_ c #4F4F4F", +"` c #4F4F4F", +"' c None", +"] c #717171", +"[ c #3C3C3C", +"{ c None", +"} c #565656", +"| c #4B4B4B", +" . c None", +".. c #939393", +"X. c #474747", +"o. c #3C3C3C", +"O. c #525252", +"+. c #B5B5B5", +"@. c #3C3C3C", +"#. c #D7D7D7", +"$. c #3C3C3C", +"%. c #F9F9F9", +"&. c #565656", +"*. c #3C3C3C", +"=. c #555555", +"-. c None", +";. c #5D5D5D", +":. c #565656", +">. c #3C3C3C", +",. c #595959", +"<. c None", +"1. c None", +"2. c #474747", +"3. c #5E5E5E", +"4. c #565656", +"5. c #808080", +"6. c #4B4B4B", +"7. c #525252", +"8. c #A2A2A2", +"9. c #4B4B4B", +"0. c None", +"q. c #C4C4C4", +"w. c #5D5D5D", +"e. c None", +"r. c None", +"t. c #606060", +"y. c #E6E6E6", +"u. c None", +"i. c #4B4B4B", +"p. c None", +"a. c #595959", +"s. c None", +"d. c #4B4B4B", +"f. c None", +"g. c None", +"h. c #606060", +"j. c #292929", +"k. c #565656", +"l. c #4B4B4B", +"z. c #474747", +"x. c #595959", +"c. c #6D6D6D", +"v. c None", +"b. c #8F8F8F", +"n. c None", +"m. c None", +"M. c #B1B1B1", +"N. c #383838", +"B. c #D3D3D3", +"V. c None", +"C. c #383838", +"Z. c None", +"A. c #6C6C6C", +"S. c #F5F5F5", +"D. c #606060", +"F. c None", +"G. c #383838", +"H. c #565656", +"J. c None", +"K. c #383838", +"L. c #4E4E4E", +"P. c None", +"I. c #474747", +"U. c #5A5A5A", +"Y. c #4E4E4E", +"T. c #555555", +"R. c #565656", +"E. c #595959", +"W. c #7C7C7C", +"Q. c #9E9E9E", +"!. c #434343", +"~. c None", +"^. c None", +"/. c #595959", +"(. c #C0C0C0", +"). c #474747", +"_. c #555555", +"`. c #E2E2E2", +"'. c None", +"]. c #606060", +"[. c #5C5C5C", +"{. c #474747", +"}. c #525252", +"|. c #515151", +" X c #525252", +".X c #252525", +"XX c #474747", +"oX c #474747", +"OX c #5C5C5C", +"+X c #555555", +"@X c #5D5D5D", +"#X c #696969", +"$X c #8B8B8B", +"%X c None", +"&X c #595959", +"*X c None", +"=X c #525252", +"-X c #4E4E4E", +";X c #ADADAD", +":X c None", +">X c None", +",X c #CFCFCF", +"o c #3F3F3F", +",o c None", +"O c #585858", +",O c #606060", +"+ c #515151", +",+ c #5C5C5C", +"<+ c #424242", +"1+ c #333333", +"2+ c None", +"3+ c None", +"4+ c #515151", +"5+ c #5C5C5C", +"6+ c #555555", +"7+ c #6A6A6A", +"8+ c #777777", +"9+ c None", +"0+ c None", +"q+ c #494949", +"w+ c #999999", +"e+ c #545454", +"r+ c #BBBBBB", +"t+ c #424242", +"y+ c #585858", +"u+ c None", +"i+ c #5B5B5B", +"p+ c #DDDDDD", +"a+ c #3E3E3E", +"s+ c #424242", +"d+ c #515151", +"f+ c None", +"g+ c #FFFFFF", +"h+ c #3E3E3E", +"j+ c #505050", +"k+ c #6E6E6E", +"l+ c #585858", +"z+ c None", +"x+ c #515151", +"c+ c None", +"v+ c #4D4D4D", +"b+ c #202020", +"n+ c #424242", +"m+ c None", +"M+ c #424242", +"N+ c #515151", +"B+ c None", +"V+ c None", +"C+ c #646464", +"Z+ c #545454", +"A+ c #4D4D4D", +"S+ c None", +"D+ c #515151", +"F+ c #676767", +"G+ c None", +"H+ c #868686", +"J+ c None", +"K+ c #4D4D4D", +"L+ c #515151", +"P+ c #676767", +"I+ c #A8A8A8", +"U+ c None", +"Y+ c #CACACA", +"T+ c #494949", +"R+ c #ECECEC", +"E+ c #3E3E3E", +"W+ c None", +"Q+ c None", +"!+ c #494949", +"~+ c None", +"^+ c None", +"/+ c #3E3E3E", +"(+ c None", +")+ c #2F2F2F", +"_+ c #515151", +"`+ c None", +"'+ c None", +"]+ c #3E3E3E", +"[+ c None", +"{+ c #737373", +"}+ c #3E3E3E", +"|+ c #545454", +" @ c #585858", +".@ c #959595", +"X@ c None", +"o@ c #585858", +"O@ c None", +"+@ c #B7B7B7", +"@@ c None", +"#@ c #3E3E3E", +"$@ c #494949", +"%@ c #D9D9D9", +"&@ c None", +"*@ c #585858", +"=@ c #3E3E3E", +"-@ c #FBFBFB", +";@ c None", +":@ c #545454", +">@ c #585858", +",@ c #4D4D4D", +"<@ c None", +"1@ c None", +"2@ c #3E3E3E", +"3@ c #494949", +"4@ c #494949", +"5@ c #3E3E3E", +"6@ c #585858", +"7@ c #606060", +"8@ c None", +"9@ c #585858", +"0@ c #828282", +"q@ c None", +"w@ c None", +"e@ c #4D4D4D", +"r@ c #A4A4A4", +"t@ c #4D4D4D", +"y@ c None", +"u@ c #C6C6C6", +"i@ c #5B5B5B", +"p@ c #E8E8E8", +"a@ c #505050", +"s@ c #6E6E6E", +"d@ c None", +"f@ c None", +"g@ c #494949", +"h@ c #454545", +"j@ c None", +"k@ c #2B2B2B", +"l@ c #5B5B5B", +"z@ c #4D4D4D", +"x@ c #6F6F6F", +"c@ c None", +"v@ c #919191", +"b@ c #494949", +"n@ c #545454", +"m@ c #5B5B5B", +"M@ c #B3B3B3", +"N@ c None", +"B@ c #D5D5D5", +"V@ c None", +"C@ c None", +"Z@ c #3A3A3A", +"A@ c #585858", +"S@ c #545454", +"D@ c #3A3A3A", +"F@ c #F7F7F7", +"G@ c #575757", +"H@ c #3A3A3A", +"J@ c #575757", +"K@ c #494949", +"L@ c #181818", +"P@ c #3A3A3A", +"I@ c None", +"U@ c #454545", +"Y@ c #535353", +"T@ c #494949", +"R@ c #585858", +"E@ c #5C5C5C", +"W@ c #7E7E7E", +"Q@ c #505050", +"!@ c #A0A0A0", +"~@ c None", +"^@ c None", +"/@ c None", +"(@ c #5E5E5E", +")@ c #C2C2C2", +"_@ c #575757", +"`@ c #494949", +"'@ c #E4E4E4", +"]@ c None", +"[@ c None", +"{@ c #454545", +"}@ c #454545", +"|@ c #5E5E5E", +" # c None", +".# c #5F5F5F", +"X# c #272727", +"o# c #575757", +"O# c #494949", +"+# c None", +"@# c #6B6B6B", +"## c #454545", +"$# c #4C4C4C", +"%# c #8D8D8D", +"&# c #454545", +"*# c #575757", +"=# c None", +"-# c #363636", +";# c None", +":# c #AFAFAF", +"># c #454545", +",# c #535353", +"<# c #D1D1D1", +"1# c None", +"2# c #505050", +"3# c None", +"4# c None", +"5# c #F3F3F3", +"6# c None", +"7# c #5E5E5E", +"8# c #454545", +"9# c #363636", +"0# c None", +"q# c #363636", +"w# c None", +"e# c #5E5E5E", +"r# c #585858", +"t# c #575757", +"y# c #535353", +"u# c None", +"i# c #4C4C4C", +"p# c #454545", +"a# c #7A7A7A", +"s# c #454545", +"d# c #5A5A5A", +"f# c #4C4C4C", +"g# c #9C9C9C", +"h# c None", +"j# c None", +"k# c #BEBEBE", +"l# c #6A6A6A", +"z# c #E0E0E0", +"x# c #5E5E5E", +"c# c #454545", +"v# c #545454", +"b# c None", +"n# c None", +"m# c #5E5E5E", +"M# c #414141", +"N# c None", +"B# c #232323", +"V# c #454545", +"C# c #454545", +"Z# c None", +"A# c #5E5E5E", +"S# c #676767", +"D# c #535353", +"F# c #4C4C4C", +"G# c #505050", +"H# c #5E5E5E", +"J# c #898989", +"K# c None", +"L# c None", +"P# c #4C4C4C", +"I# c #ABABAB", +"U# c None", +"Y# c #CDCDCD", +"T# c None", +"R# c #5E5E5E", +"E# c #EFEFEF", +"W# c #4C4C4C", +"Q# c None", +"!# c None", +"~# c #4C4C4C", +"^# c #5E5E5E", +"/# c #505050", +"(# c #4C4C4C", +")# c #323232", +"_# c None", +"`# c #545454", +"'# c None", +"]# c #767676", +"[# c None", +"{# c #5E5E5E", +"}# c #989898", +"|# c #696969", +" $ c #5B5B5B", +".$ c None", +"X$ c #5B5B5B", +"o$ c #5A5A5A", +"O$ c #BABABA", +"+$ c #3D3D3D", +"@$ c #414141", +"#$ c None", +"$$ c #DCDCDC", +"%$ c None", +"&$ c None", +"*$ c #414141", +"=$ c #FEFEFE", +"-$ c #656565", +";$ c #414141", +":$ c None", +">$ c None", +",$ c #535353", +"<$ c None", +"1$ c #414141", +"2$ c None", +"3$ c #505050", +"4$ c None", +"5$ c #636363", +"6$ c #484848", +"7$ c #5A5A5A", +"8$ c #858585", +"9$ c None", +"0$ c None", +"q$ c #505050", +"w$ c #A7A7A7", +"e$ c #656565", +"r$ c #535353", +"t$ c #C9C9C9", +"y$ c #5A5A5A", +"u$ c #4F4F4F", +"i$ c #535353", +"p$ c #EBEBEB", +"a$ c #3D3D3D", +"s$ c #5E5E5E", +"d$ c #505050", +"f$ c #575757", +"g$ c None", +"h$ c #2E2E2E", +"j$ c None", +"k$ c #505050", +"l$ c None", +"z$ c None", +"x$ c #727272", +"c$ c #484848", +"v$ c #949494", +"b$ c None", +"n$ c None", +"m$ c #484848", +"M$ c #B6B6B6", +"N$ c #D8D8D8", +"B$ c #565656", +"V$ c #3D3D3D", +"C$ c #575757", +"Z$ c #5A5A5A", +"A$ c #3D3D3D", +"S$ c #FAFAFA", +"D$ c #565656", +"F$ c #3D3D3D", +"G$ c #4C4C4C", +"H$ c #3D3D3D", +"J$ c None", +"K$ c #575757", +"L$ c None", +"P$ c None", +"I$ c #5F5F5F", +"U$ c #5A5A5A", +"Y$ c #4C4C4C", +"T$ c None", +"R$ c #5B5B5B", +"E$ c #818181", +"W$ c #A3A3A3", +"Q$ c None", +"!$ c #616161", +"~$ c #C5C5C5", +"^$ c #4C4C4C", +"/$ c #575757", +"($ c #5A5A5A", +")$ c #E7E7E7", +"_$ c None", +"`$ c None", +"'$ c None", +"]$ c #616161", +"[$ c #4C4C4C", +"{$ c #444444", +"}$ c None", +"|$ c #616161", +" % c #4C4C4C", +".% c None", +"X% c None", +"o% c #4B4B4B", +"O% c #2A2A2A", +"+% c #4F4F4F", +"@% c None", +"#% c None", +"$% c #4C4C4C", +"%% c #6E6E6E", +"&% c #4B4B4B", +"*% c None", +"=% c None", +"-% c None", +";% c None", +":% c #909090", +">% c #5D5D5D", +",% c #6D6D6D", +"<% c #B2B2B2", +"1% c None", +"2% c #484848", +"3% c #D4D4D4", +"4% c #484848", +"5% c #393939", +"6% c None", +"7% c #F6F6F6", +"8% c #393939", +"9% c #575757", +"0% c #393939", +"q% c None", +"w% c #616161", +"e% c #393939", +"r% c None", +"t% c #444444", +"y% c #5D5D5D", +"u% c #484848", +"i% c #5B5B5B", +"p% c #4B4B4B", +"a% c #535353", +"s% c None", +"d% c #4F4F4F", +"f% c #7D7D7D", +"g% c #484848", +"h% c #9F9F9F", +"j% c #5A5A5A", +"k% c #C1C1C1", +"l% c #4B4B4B", +"z% c #E3E3E3", +"x% c #525252", +"c% c #535353", +"v% c #565656", +"b% c #5D5D5D", +"n% c #4F4F4F", +"m% c #444444", +"M% c #535353", +"N% c #484848", +"B% c #6C6C6C", +"V% c None", +"C% c #262626", +"Z% c None", +"A% c #444444", +"S% c #484848", +"D% c #565656", +"F% c #6A6A6A", +"G% c #565656", +"H% c #444444", +"J% c #8C8C8C", +"K% c None", +"L% c None", +"P% c #535353", +"I% c #444444", +"U% c #AEAEAE", +"Y% c #D0D0D0", +"T% c #4B4B4B", +"R% c None", +"E% c #353535", +"W% c #616161", +"Q% c None", +"!% c #4F4F4F", +"~% c None", +"^% c #F2F2F2", +"/% c None", +"(% c None", +")% c #353535", +"_% c #5D5D5D", +"`% c #535353", +"'% c #444444", +"]% c #616161", +"[% c #353535", +"{% c #444444", +"}% c None", +"|% c #5D5D5D", +" & c #575757", +".& c #404040", +"X& c #444444", +"o& c #535353", +"O& c #797979", +"+& c #696969", +"@& c None", +"#& c #565656", +"$& c #444444", +"%& c #9B9B9B", +"&& c #696969", +"*& c None", +"=& c #5A5A5A", +"-& c #BDBDBD", +";& c None", +":& c None", +">& c None", +",& c #DFDFDF", +"<& c #404040", +"1& c #444444", +"2& c #535353", +"3& c #4B4B4B", +"4& c None", +"5& c None", +"6& c #222222", +"7& c None", +"8& c #444444", +"9& c None", +"0& c #5D5D5D", +/* pixels */ +" ", +" V+/@. ' F./%:&L =# .z$v.HXCO6%-%1.. s V+ ", +" o G+iO4$.$n$% B%i+PoE.5+d &o4.}o}o9@c X$,+|oPokX^oaXCo'#>&r.8 ", +" o 9 ^+m+@+0 UOm@co!+2.s#g @.JoP@K.K.fOfOfOfOK.e%IoDo#@@$I.m$-+f$Z$(@j#.H$H$H$H$H$>.IoP@K.fOq#[%q#fOe%@.$&4@Q@so#%4&sXNXOO ", +" V+b#& !#_oG $@w H@fO[%fOP@H$1$X O#z@k$q 6+ &r#hOhOhOhOr#rX`#k$z@;OQOM+5@P@fO[%[%e%=@8#P#t#~ Uog.4OV+ ", +" V+MORo> v%q+2 0%[%q#e%5@C#l._+ &E@7@C+S#S#/O#XF%1Oc.1O1O1O1OF%#XS#O C+1oEohOq $%QOM P@fO[%K.A$pO!%^ NOw#jOV+ ", +" OOP y@t.d%H%D@q#[%P@1$S%_+hO7@ZX/O@##XS#F%] ] ] x$e W.0@# # E$a#e ] ] ] vo#XO /O/OZX1oU.q ;OM+Ioq#[%e%i g@r$U+;%jOOO ", +" OOYO+Ob%Y.WXfO0Xe%M S%`XE@5$#XF%/O1O%%W.J%v@w+* +@lX-&-&ZO)@q.q.k%ZO-&lXr++@I+[X:%$XO&%%@#S#/OC+3.`#;O1$P@[%q#*.##R X%Ko@@V+ ", +" o iOKo(Of#/+9#[%IoX ` i%ZX@#@#@#c.f%$XQ.+.ZOI - .+.+.+.+Y%Y%,XY%Y%Y%Y%Y%Y%,X.+Y#Y#- Y+~$lX<%%&J#cO1OF%/OO Eo_+oXH$q#[%Jo##i$no'#~% ", +" G+1@K#&%WX9#q#>.oX`#I$#X@#@#c.f%[X8O-&t$- .+<#Y%<#wO3%B@B@Zo#.#.N$N$N$#.#.#.Zo3%B.wO<#Y%,X.+Y#PXwor+|Ov@cO1O#XO 1orX;O>oq#[%$.z.Z+I@*%-O ", +" OOYO#+,.U@eO[%IoQOq 7@#XF%@#8+5O* k#t$Y#,XY%wO3%#.N$%@.o$$$$xXxXxX,&,&,&,&xX,&xXp+$$$$.o%@N$Zo3%B.<#,X.+- wor+6o# e #XS#5$ &;O5@q#q##@~#o$r%MOo ", +" -OV@>%5X[ q#e%X `X7@#XF%@#cOg#O$woY#,X<#wOZoN$%@$$p+,&z#FO`.'@ O O Oy.y.)$)$y.y.'@'@'@`.FOFO,&xX$$%@N$ZoB@wO,XY#PXq.Bo.@8+#XS#V rXoXIo[%e%I%*o%$1@8 ", +" jOV.y#.&9#q#1$` 3.#XF%1OW@h%-&Y+,XY%3%Zo%@h p+,&FOz%'@)$p@p@E p$R+YX, , , E#E#, YXYXR+R+p$yoyo)$'@z%FOz#p+$$%@Zo3%<#.+- I ofXa##XO 7@q X K.q#A$W y$C@qO ", +" OO$+9+l%mo[%>.S%hOS#1O@#W.`oZOPX,X<#B.N$h p+,&`.'@y.p@p$YX, %+1X^%tOS.7%FoF@F@F@F@F@Fo7%tOtO^%^%1XE#YXp$p@y.'@`.FOp+$$%@B@wO,XY#t$lX%&dX#XO Eo$%H$q#e%o0XH@4%VoKX]O ", +" iOu#a@do[%M k$V 1OF%5.8Ot$,XwOZo.oxXz%y.E YX1XtOFoS$#o-@%.^%)$#.k#`o# {+1oU.rX_+koko` k$ko$%;Ol.$%` `#7@{+J#6o'oh p$7%-@#o-@%.S.1XYXyoy.z%,&h #.3%,X- q.w$cOF%C+q M+q#K.8#T.q@qO ", +" ;#/ $#Soq#BX6+O @#%%MolX- <#B@%@p+FO OE YX1XS.%.-@#o%.tOy..+I## @#Eo &i%5$/Ox@x$e e e ]X{+x$voc.@#/O5$EorX` O#O#6+F%$XM.3%p$7%-@#o%.7%^%, yoy.`.xX.oB@<#Y#I +.[O@#O r#C#fOfOqXD#!#0# ", +" ^+QXT%8%fOX r##X@#x$!@~$.+<#Zoh ,&z%y.R+1XS.%.#o#oFo, .o+@J%/OU.3.F%]#/oS H+H+8$4o0@5./of%cOO&dX8+e {+x$voc.@#S#I$r#rX3.@#8+p k#z#5#-@#oS$7%1XYXp@'@z#h N$wO.+Y+ZOp x@S#i%S%K.q#<+&+(%qO ", +" G+wX#O5%q#X r#F%F%e H I .+B.#.$$FO OE YX^%Fo#o#oS$E#B@JXa#I$I$x@/o# %#5O%#$X[O# H+8$4o0@5./of%cOO&dX]#]Xx$] vo%%x@O&MoU%O$:#.@O&x@H+BoxXtO#o#oFotOE#E y.FOxXN$3%Y%PX)@BOvoS#E@S%K.fO{%)Oq@G+ ", +" 9 V%eoZ@fOX hOF%@#W.U%Y+,X3%%@xXz%)$R+1XS.%.-@S$1XZo6o]X3.#X5.%#v$.@..v@b.5OJ%J## H+8$4o0@5.W@W.cOO&dX]#]X] voe H+`or+Y+.+.+,XPXk%JX8$x@5.8OxX7%#o-@S.1XYXp@'@xX.oB@Y%- 'or@]XO EoO#K.fOX&_@;+J+ ", +" -OFX|.loq#X r#F%F%E$BoPXY%Zo.oxXz%yo, 5#Fo#o-@tOxX:#]#I$x@J#[XfXw+}#p v$Mob.J%J#GX8$4oE$5.W@W.cOa#dX]#]Xx$x$a#%#* lX~$wowoY+- Y%<#wO<#t$<%J%x@4oO$y.Fo#oFotOE#E Oz#$$#.wO- u@I#8+O EoO#K.K.kOU$Z#OO ", +" V+Z#D$a+)%BXr##X@#5. o- <#Zo$$z# OE E#S.S$#o%.E k%H+7@c.J%g#h%BOg#%&w+p .@:%J#E$cO8+e {+x$] x@%%c.1OF%/O#X{+GXw+w$JX* * ;XM.r+~$Y#wOB.3%B@3%Y#M@S %%v@PX1X#o-@7%%+p$y.FO$$#.wOY#woU%8+S#E@oXfOK.b@AO_$V+ ", +" +|@M#[%M rX#XF%cO+.- <#Zo.oFOy.p$%+7%-@#o7%,&6o#XZX8$BOW$8.`oh%BOg#fXp v$J%W.@#3.hOrX6+`#q `X_+_+k$k$r#ZXx$8+8+8+dXdXO&f%J#BOM$I Y%wO3%B@B@B@B@t$r@]#]X:#p@S$-@F@1Xp$y.FO$$#.wO- wo* ]XO i%X [%H@(#c+2X ", +" NX}%X.q#H$`XS#@#]X|OPX<#Zoh z#y.p$1XF@#o-@^%<#5O1oO&fXH w$H r@W$`oQ.g#%&p MoS F%` H$q#1+)#)#)#5 (X)#[%IoM M+M+M+1$BXBXBXX ;OE@/ow$k%.+wO3%B@B@#.#.#.B.ZO:%c.%&h 7%#oFo^%R+)$`.h Zo<#- u@r@x@O r#1$[%2@9O(+qO ", +" -Oc@p%-#P@$%C+1Ox$H t$Y%Zoh z#y.R+1XF@#o-@YXlX8+5$J#H I#* I+w$H r@8.h%BO%&}#:%W.hOK.k@) fofofok@fo) )+(X(X(X(X(X(X(X5 (X5 )#(XBXx@!@(.Y#wO3%3%B@#.#.N$%@.oY+5OrXO&wotO#oFo^%YX)$FOh #.<#- ~$Q.%%C+`XH$[%zX+XX@f+ ", +" V+&$vOmoq#oXI$1O%%h%t$,XB@h z#y.R+^%Fo#oS$E :#/Ox@w+;X:#U%|O* I+H r@8.!@Q.g#}#%#{+$%) /OO$k#k#k#k#ZOZOZOZOZOZOZOZOZOZOZOZOZOBo_+5@] r@)@- wOB.3%B@Zo%@#.- M.Moe i%C#C+O$%+#o%.5#YXy.FO$$Zo<#Y+'o.@#XV z@e%fOyO< &@o ", +" GOzoyX[%M+hO1OF%:%q..+B..oz# Op$1XFoz S$p@I+S#a#H <%<%M.:#;XI#JXw$6oW$`o!@BOp GXF%1$) ;Xz z -@#o#o#o#o#o#o#o#o#o#o#o#o#oz g+N$$%QOf%;X~$Y#<#wO3%B@<#-&!@0@] 1O1O@#I$oXE@M@, #oS$^%R+y.FO$$B@,Xt$k## #X3.oXq#IoAXR%^+ ", +" -O%X5Xq#>.`X/OF%/or+- wON$,& OE %+F@#oS$y.r@O E$|OM$+.M@<%8OU%|OJXI+H r@W$!@BO.@E$E@fO5@3%S$p+<#B.B.3%3%B@B@ZoZo#.#.N$%@.oYX=$M@e%`X[O+.I .+<#wO~$:#v@cOx$vox@%%c.1OF%1oO#hO:#, #oFo^%p$y.FO.o3%.+I M@dXZX &1$[%*$j J$OO ", +" 1#J@bofOO#V @#] U%- <##.p+z%yo%+7%#o%.)$r@S## 8Of o+@+.<%M.:#|O* JXw$6or@!@p [OdXhO1+V R+%+q.f r+r+lX-&k#ZO(.k%)@'oq.q.I p$%.J%q#I$[XlX- Y+O$BO8$8+]X{+{+] x@x@%%c.1OF%1o;O &M.E##oF@%+E '@,&%@B.- u@W$c.5$` P@K.K@h.,o ", +" b#N#t%[%M+U.1OF%fXwoY%Zo$$FOp@E#7%#o#op$JXS#J#+.lXr+f oM$M@M.8O;XI#JXI+`ofX[Xw+w+E$ &(X# %.)$k#lX-&k#ZO(.k%)@'oq.~$~$u@wo,XS.YX7@>.%%`o+.I+v@f%8+]#]#e {+x$x$vox@%%c.1O@##XV ;Oi% o5##o7%%+yo`.p+#.Y%Y+)@v@S#I$oXq#H$n%% G+ ", +" OOgXo%eOP@k$/O@#0@ZO.+3%.oFOy., tO-@-@YX8O#XH++.ZOk#lXO$f M$Bo<%M.:#* 8.fXfX`oI#I#g#dX;O0XM$-@h k#-&ZO(.k%)@'oq.~$u@u@woI I .o-@B.C#X 1OE$W@a#O&a#O&dX]#]#]X{+x$] vox@%%c.F%#X#X1oO#1ok%7%#o7%, p@FOh B@,XY++@cOO &>oq#1&x.7oV+ ", +" P KOE+q#QO7@1O] |OPXwON$xX'@p$5#%.#otOk#@#0@M$)@k%(.k#lXf +@M$M@U%8.g#g#6o|O:#U%JXv$c.5@C##.%.Y%ZO(.k%)@'oq.~$u@woI I t$Y+PX Oz JX5 H$hO%%O&cOcOa#O&dX8+]#e {+{+] vox@%%c.1OF%F%#XI$oXc.<#S$S$tOYX O,&%@wOY#u@8.c.V $%fOP@A+2OiO ", +" V++ i#9#>.q @#F%v@~$,XZop+z%yo%+Fo#oF@3%cOdX+.q.q.)@k%ZOlXO$+@U%r@fXh%6oI#;X;XU%;Xr@$X1o1+#XYX1Xt$)@'oq.q.~$u@woI t$Y+PXPX- Y%E#F@/o$OM+7@e W.W.W.cOO&O&8+]#e ]X{+x$vovox@%%c.@#F%#X/OE@C#8$z%-@%.^%E '@xX#.Y%Y+ZO# S#hOM [%s+G%]oV+ ", +" =%Woa$q#oX1o@#dX+@- wO%@FO)$YXtO-@S$`.v@c.|Ou@wo~$q.)@(.f ;X!@BO`oH JX* * |O;X;XI#h%5.`#h$5O%.p@~$q.~$u@woI I t$Y+PX- Y#Y#.+#.F@ O`#) l.S#dXf%f%W.cOa#O&8+]#]#e {+x$] vovo%%c.1O@##X/OS#E@U.H , z S.E#yo`.h 3%Y#I :#{+5$koe%e%v ]@`$ ", +" V+=oL.)%H$rXF%@#BOt$Y%#.p+'@p$^%%.#oYXJX#XQ.I Y+t$woq.f I#Q.BO8.6ow$I+JX* * |O|O|OI+p ]XoXq#O$-@p+~$u@woI I t$Y+PX- Y#.+,XY%Y%z##ot$K.0X`#x@cOW@W@W.cOa#O&dX8+]#e {+{+x$vovox@c.1O@#c.W.w+Bo}#volXF@-@5#R+y.,&N$<#PXq.v$/OU.M+[%t+a.(oo ", +" jO`+h+q#O#5$@#cO-&.+B.h FOp@E#F@#o7%~$] 5O~$Y#- q.+@6oQ.Q.`or@6oH H I+I+JXJXI#|OI#H b./O>.;O$$%.B.woI t$Y+Y+PX- Y#.+,XY%<#wOB.R+-@g#k@H$E@e f%W@W@f%W.cOa#O&dX]#]#]X{+x$] x@x@%%e [OI#I N$h PXJ#f%N$-@Fo1XE z%p+B@,Xt$Boe V koK.P@v+]@/@ ", +" V+L#u$E%H$6+@#@#g#Y+Y%#.xX'@R+tO-@#o`.$X8+r+Y#q.8O8.g#Q.`oW$W$r@r@6oH I+I+JX* * I#* `o8$E@)#vo%+1X.+t$Y+PX- Y#.+.+,XY%<#wOB.B.N$tOtO{+$OQOC+dXW@/o/of%W.cOa#O&dX8+]#]X{+x$x$x$f%}#+@Y%%@h h h N$O$]XQ.%+-@S.YXy.,&%@wOPXq.v@S#U.1$q#1&l@m+ ", +" s '.!.[%oX1o@#O&O$.+B.h FOp@%+Fo-@^%+.%%!@r+|OBO%&BOQ.!@!@8.W$r@r@6oH w$I+I+JXJXI#I+g#cO_+)+w+-@p@- PX- Y#.+,XY%<#<#B.B.B@B@Zo,&S$xXkoh$ko@#cO5.5./oW@f%W.cOa#dX8+]#e {+dXJ#6o'o<##.%@.o.o.o$$h B.Q.x$I S$%.1XE z%$$B@,XI 8Ox$1o$%fOH$ XuX8 ", +" g.QoD@e%`XF%F%}#I Y%#.p+'@R+tOS$%.h cO] }#fXw+g#BOQ.Q.h%!@`o8.W$W$r@H H I+I+JX* * 6o.@voX P@k%#o,&- .+.+,XY%<#wOB.3%3%Zo#.N$%@p@z (.1+fOr#] W@E$5./oW@f%f%cOa#dX]#]#5.v$Bot$B.B@B@#.N$N$%@.oh $$.oI /oJ%yo#oS., y.,&N$<#PX)@%#S# &5@q#`@e#MO ", +" f+c@iX[%M+3.1Oe +.Y#3%.oFOp@%+Fo-@^%|Oi%5.[XfXfXg#BOBOBOh%!@`o8.W$W$r@6oH w$I+I+JXJX8.J%C+K._+z%Fo#..+,XY%<#wOB.3%B@ZoZoN$%@%@$$1X%...O%1$1o]#5.0@E$5./of%f%a#dXcO[Or@(.Y#wOB.B.3%B@#.#.#.%@%@.o$$$$%@8Ox@-&%.%.1XE `.h B@.+wo|O%%7@oX[%;$y+'+ ", +" iO<.= q#$%S#1O[O~$,XZop+z%p$5#-@S$.o8+O v@p w+fX%&BOBOQ.Q.!@!@8.W$W$W$r@H H I+JXJXw$Q.4or#(XO&tO1XB.Y%<#wOB.3%B@Zo#.N$N$%@.oh z#F@1X#Xj.;O/OcOE$0@E$5.W@f%cO4ov$<%woY%<#Y%<#wOB.3%B@B@#.N$%@.o.o$$$$h ,X8$[Op@-@7%YX OxXN$<#Y+lX5.ZX_+e%P@K+w@4O ", +" _Oj+0OIo6+1O1OH PXwO%@z#y.E#7%#o^%:#i%/o[Xp }#fX%&BOBOQ.Q.h%!@`o8.8.W$r@6oH w$I+JXH [Xx$C#foH #op@wOB.3%3%B@Zo#.N$%@.oh $$p+p+)$#oN$S%5 q x@W@0@4o0@W@/oJ#W$O$Y+.+.+.+,XY%Y%wOwOB.B@B@#.#.N$.o.o$$$$h .o;Xx@)@%.%.1Xp@FOh B.Y#q.}##XU.M q#).J ,o ", +" 8 K%X.[%M+3.@#cOO$Y#3%$$z%E 1X%.S$p+f%V 5O[Xp }#w+fXg#BOBOQ.h%!@!@8.8.W$r@6oH w$JX8.[X/oI$Io5@Y+#o`.3%ZoZo#.N$N$%@h $$$$xX,&,&,&YX=$O$)+e%E@e E$0@5.0@..* k%Y+PX- - .+.+,X,XY%<#wOB.3%B@Zo#.#.%@.oh $$$$$$- /o:%p$#o5#p$'@xXZo.+wo8Ox$7@S%[%b {XJ$V+ ", +" qO%O6 fOl.O @#:%wo,XZoxX OYXtO#o7%-&I$dXv$p p }#w+fX%&BOBOQ.Q.h%!@8.8.W$r@6oW$BO[X..Mo8$7@[%U.E Fo$$ZoN$%@%@.oh $$p+xX,&z#FOFO'@S.%.5OO%M+5$8+W@GX%&Bo'ot$I t$Y+PX- Y#.+,XY%Y%Y%wOwO3%3%B@#.#.N$.o.o$$p+p+N$Q.1O.+-@F@, )$z#%@<#Y+k## ZXk$e%P@K { 8 ", +" ;@uo0OIo`#@#@#I#- <#%@FO)$E#Fo#op$v$E@# v$p p }#}#fX%&g#BOQ.Q.h%!@`o8.8.h%}#.@w+6ow$Q.5.`#(XS F@^%%@N$.o.o$$$$p+xX,&,&z#FO`.z%p@S$E#V O%S%O 4oh%Bo)@'ou@wowot$Y+PX- - Y#,X,XY%Y%<#wOB.3%B@Zo#.#.%@h h N$q.r@]Xl.W$S.S$1Xyo`.$$3%- ~$g#/OhO>ofOg%].P ", +" goi#[%1$E@c.8+f .+3%$$`.yo^%S$S$3%1OF%:%.@[Xp }#}#fXfX%&BOBOQ.h%!@h%fX[Xp W$|OM.:#JX}#]#S%)#<%z p$.o.o$$$$p+xX,&z#FO`.`.z%'@ O, z 3%1$)+r#4o!@I+|O<%O$(.~$woI Y+Y+- Y#Y#,X,XY%Y%<#wOwOB.B@ZoN$%@#.Y#<%v@]#F%C+oX]#z%-@5#p$'@xXZo.+wo8O{+3.C#[%;$+Xl$ ", +" 8 [@{$[%oX5$#X# u@,XZoxX OR+tO#o7%<%U.cOMo.@.@p p }#w+fX%&g#Q.BOfX[X[X!@* BoBo<%M.:#w$..1O5@C#wO#oy.h p+xX,&,&FOFO`.z%'@ Oy.)$p@5#=$M@k@P@7@dX/o/o8$Mor@BoZOu@I Y+Y+- - Y#.+.+,XY%Y%wOwOB.ZoZoB.(.`o4ovo@##X#X#X`#6+~$S$7%, y.z#N$Y%t$lXdXV l.q#F$} N@V+ ", +" r.y%]+fOz@/O@#p PXY%#.z#)$E#7%#oR+:%E@GXMov$.@p p }#}#fX%&fXp [X%&w$M@f oM$BoM@M.U%r@$X1o0X5$YXFo`.xX,&z#FO`.z%'@ Oy.y.)$p@yoR+FoFo8$mX5 QOk$` $%q O E$`o oq.wot$Y+Y+- - Y#.+,X,XY%<#3%3%t$:#v@a#x@1O1O1O@##X#X3.S%!@S.%.1Xp@`..owOPXk%5OO `XP@e%!Xq%8 ", +" 2XB$N.Io`##Xc.8O- wO.oFOyo1X%.#o$$x$/O%#Mov$v$[Xp }#}#.@.@p 6oM@r+lXr+O$ o+@+.M@M.;X!@0@6+5 [OFotOFOz#FO`.z%'@ Oy.y.p@yoyoE p$E##op$6+L@6&j.O%0X6+# I$1o%#:#)@u@I Y+Y+- - Y#,X.+,XwO- r+Q.S ]Xx@x@x@%%c.1O@##X#XZXoXcOE -@5#p$z%$$B.Y#u@h%ZXr#5@q#Yo|#9$ ", +" [+y+aO>oU.1O{+O$.+B.h `.p$5#-@%.~$I$e b.v@..v$[X[X.@.@8.U%lXk%k%k#lXO$f f +@M$BoM.I#%&dXO#1+M$z E#FO`.z%'@ Oy.)$p@p@E p$p$R+YX5#z PX5 6X-oP@voI#p+wo;O`XS |O(.u@I t$Y+PX- Y#,X.+)@I+%#O&{+x${+x$] x@%%c.1O@#F%#X/Ok$7@#.#oS.YX OxXB@.+wo;Xx$EoM+[%QO!oSX ", +" hXX+[%BXI$1OH+)@,XB@$$'@YXS.#oS.JXr#5.:%MoMo....BO|OlXq.~$)@k%(.ZO-&r+O$f +@M$+.M.JXv$c.5@O#B@#op$z%'@ Oy.)$p@yoE p$R+R+, E#%+F@z I+5 r#[X<#1X#o#oI+0X`#GXU%(.u@I t$Y+Y+- u@Bo%&5.8+]X]#e ]X{+x$] x@x@c.c.1O@##X#XhO$%lXS$F@, y.,&#.Y%t$r+a#3.S%q#b r & ", +" 7&h@[%S%C+/O5Ot$Y%#.xXy., 7%z , b.i%# :%:%p H o~$Y+t$wo~$'o)@k%ZO-&lXr+O$f M$+.8OH J%V 0X#XE#S$yo O)$p@yoE p$p$R+, E#E#%+1X5#-@#o,X'oE -@g+=$g+tOa#0X3.:%M@k%u@wot$t$-&6o[OW.8+dXdX8+]#e ]X]X{+x$vovo%%c.1O1OF%F%1ooXh%7%Fo%+p@z#N$<#Y+k#a#1oz@fO5@:@8@ ", +" -O:$>#fOl.S#S#v@- <#%@,&)$E#Foz OW.5$J%Q.M.'o.+.+- PXt$wou@q.'o)@(.k#lXr+f o+@M$8O`o0@6+)#:%%.7%)$p@yoE p$R+YX, E#%+1X1X5#5#7%=$g+z =$=$z #oz g+y. &P@1Ow++@'ou@)@:#[X0@a#cOcOcOa#O&dX]#]#e ]X{+x$] vox@%%c.1O@#F%ZXQO8$1XS$^%E FO.owOPXk%H+O k$e%>.R.HOOO ", +" iOGoXofO` F%%%h%- wO.oz#p@1X%.#oh 1O5.O$Y#wOwOY%,XY#- Y+I u@~$'o)@k%ZO-&lXO$f oM$:#g#8+O#K.k#z 1XyoE p$R+YX, E#%+1X^%5#tOS.7%S$=$=$=$#o#o#oz =$g+q.5@QOO&r@O$+.`oGXf%W.W@/of%W.cOa#O&O&8+]#e ]X{+x$] vovo%%c.1O@#F%/O;Ovoy.-@5#p$z%h B.- q.fXO `#Ioe%$oW+9 ", +" 1.PoSoe%q F%] M.- B..oFOyo^%S$-@PX%%I#B.B.B.<#Y%,X.+- Y+t$wo~$'o)@k%(.k#-&r+f o+.|O.@@#H$koh z E#p$R+YX, E#%+1X^%5#tOS.7%F@Fo-@#o#o#o#oz =$g+g+z !@)#q 5.[XJ%E$W.5.0@E$5./oW@W.W.a#a#O&8+]#]#e {+x$] vovo%%%%1O@#F%#Xk$5$.o-@tOp$'@$$3%Y#u@W$ZXr#H$fOYo:X;o ", +" 1.Y@5%IorX#Xx$O$Y#B.h `.E ^%-@%.r+]#f B.3%B.wO<#Y%.+- PXY+I ~$q.'ok%(.ZO-&r+f +@Bow$H+r#h$x$^%S$, YXE#%+%+^%^%5#tOS.7%F@Fo%.S$S$#oz z =$=$g+g+g+5#{+1+ko/O]X/oS 8$4o0@E$5./o/of%W.cOa#O&dX8+]#e ]X{+x$] x@x@%%c.1O@#voF%5$Y##oS.YX Op+B@.+wor@ZXi%M q#&O'XbX ", +" @@x%eOH$r#F%voO$.+3%h `.p$tO#oFo8O8+ZO3%B@B@B.<#,X,XY#PXY+I u@~$'o)@k%ZO-&O$ o<%r@GXO X )+fX-@Fo%+%+1X^%5#tOS.7%F@F@%.S$S$-@#oz =$=$g+g+g+=$^%B@%&M 1+`XvoE$8$H+8$S 4o0@E$5./oW@f%cOa#O&dXdX]#e e {+x$x$vox@%%%%O&..M.U%1O'o-@S.YX Op+B@,XwoH /OE@1$[%O#s@j@ ", +" TOy+K.5@U.1Ovor+.+B@$$z%p$S.#oF@JX8+)@B@ZoB@B.wOY%,X.+- Y+t$wou@q.)@(.k#O$8OQ.$XcOx@r#P@e%u@=$7%^%^%5#tOS.7%F@Fo%.S$-@#oz z =$g+g+g+=$7%xX|O] M h$0XO#C+a#S GXH+H+S 4o0@0@E$5.W@f%W.cOa#O&dX8+]#e {+{+] vo{+4o8.u@N$%@r+1Or+-@F@YX OxXZo,Xwo* c.3.M+[%S%rO}$ ", +" ~oo@K.>oE@c.{+lX.+B@$$'@R+S.#oS.W$dXq.B@#.Zo3%wO<#Y%,XY#PXY+I u@q.k%r+|O[X5.dXvoO q H$C%` z%z tO5#tOS.7%F@Fo%.S$-@#oz =$g+g+g+g+%. Of 5.l.)+foq#BX`XC+]#E$H+# GXH+8$S 4o0@E$5./of%f%cOa#O&dXdX]#e {+{+a#v@<%- %@$$$$#.O$%%<%%.F@, y.p+#.,XI U%{+7@BX[%S%&& # ", +" !O>@fO>oEoc.8+-&.+Zo$$'@R+tO-@tOBOO&~$ZoN$ZoB@B.<#Y%,XY#PXY+I u@-&* :%/o] #Xi%z@H$5 h$M+p F@#oS.S.7%F@Fo%.S$-@#oz z g+=$=$=$=$S.8.`X(Xj.1+M z@U.O ] W.S GX# J#GXH+8$S 4o0@E$5./oW@f%W.a#O&dX8+]#8+S Q.k#<#ZoN$%@h h 3%f ] |OF@F@, )$xX#.,XI M@8+7@X [%oX8oZ% ", +" ( 6@fOM Eo%%W.k#.+B@$$'@R+tO-@^%w+W.woZoN$#.Zo3%<#Y%,X.+- I lXI+[X[O/oc.rXM+0X)+>.ZX`oB@S.=$-@F@Fo%.%.S$-@#oz =$=$=$=$z #o#og+%@>ob+[%S%rX5$voO&5.8$J#[O[OJ#J## H+H+S 4o0@E$5./oW@f%W.cOa#8+W.%#|O'oY%wOB.B@ZoN$.o.owOf e I+F@F@, y.xX#.,XI M$O&3.X [%QO@X+O ", +" TXK$fOM Eoc.W.k#.+B@p+'@R+tO-@^%fXW.wo#.%@N$Zo3%wO<#<#I o8.p .@p J%] `XfOfO`#J%u@, #o=$z -@S$S$-@#o#oz =$=$=$=$=$#o#o-@S$#o=$r+) 1+` S#]#5.H+[OJ%%#%#J%$X[OJ## GXH+8$S 4o0@E$5./oW@a#a#E$w+M@u@Y#.+Y%Y%wO3%B@#..o%@<#f 8+JX7%F@, y.xX#.,XI M$O&3.X [%oX.#'$ ", +" LO*@fO>oE@c.]#lX.+B@$$'@R+tO#otOQ.a#woN$.o%@#.Zo<#u@U%%&..p %&g#[XS 5$>.M+I#z%%.g+=$#oS$S$S$-@#oz =$=$=$=$=$z z #o-@S$S$%.z S$$X$OBXO /o$X5O:%:%:%b.5O%#J%[OJ#J## H+H+S 4o4o0@/ocOf%$X8.f u@Y+Y+- .+,X,X<#B.B@#.%@N$wOf ]X;XFoF@, y.xX#.,XI <%8+7@X [%oX5od@ ", +" P.t K.5@U.@#] O$.+B@$$'@p$tO#o7%W$8+u@%@h %@wOlXH [Xv$[Xw+fX%&fX..W.r#1+x$^%=$#oS$%.%.%.S$#oz z g+g+=$=$z #o-@-@S$%.%.Fo%.z , C+fo_+]X$X......Mov@b.b.5O%#$X[OJ## H+H+8$4o5.f%0@..U%-&q.~$woI t$PXY#,X,XY%B.3%ZoN$%@3%f %%+.S$F@, y.xXZo,Xwo;Xx$3.BXq#S%+&IX ", +" 0+ROG.H$r##Xx@O$.+3%$$`.p$S.#oFoJXdXu@N$Y#M$BO..v$p }#}#}#fXfX}#5O{+z@)+!@#o#o%.%.S$-@#oz =$=$g+=$z z z #o-@S$%.%.FoF@7%%.=$3%>o[%E@/ov@.@.@..Mov@:%b.b.%#J%$XJ#J## 8$E$W@# Q.M.ZOk%k%)@q.u@wot$Y+- .+,XY%wOB.B@N$%@B@ o@#-&-@7%, Op+B@,XI JX1OE@1$[%;O,%ro ", +" ' Y@C.IorX#X] O$Y#3%h `.E 5#-@Fo<%]#;X* w+:%...@p p p }#}#fXw+[XJ#F%M+P@)@=$-@-@#oz =$=$g+g+z z #o#o-@-@S$%.FoF@F@7%7%S.%.z M.) >oS#8$..[X[Xv$..Mov@b.b.5OJ%J%J#H+E$0@b.6oM$r+-&k#ZOk%)@'o~$u@I Y+- Y#,XY%<#B.B@#.N$B@M$c.q.-@S.YX'@$$B@.+I H S#i%M q#l.U u. ", +" 1.PoZ@P@`#/Ox$ o- 3%.oFOyo^%S$S$(.5$W.b.v@..v$.@[Xp p }#}#w+w+v$S V P@q z%=$z =$=$g+g+g+=$z -@-@S$S$%.%.FoF@7%S.S.S.tOtO-@Fo4ok@;O] $X.@p [X.@..v@v@:%b.b.%#H+0@8$p * Bo o of r+-&k#(.k%)@q.u@wot$PX- .+,X<#wO3%B@ZoB@U%{+.+-@S.R+z%$$B@Y#u@r@C+r#5@fOi.k+*& ", +" 1.=.V$K.k$/O] ;XPX<#%@FOyo1X%.-@Y%7@x$:%MoMov$[X.@[Xp p }#}#w+..E$EofOdXtOg+g+=$7%$$yog+z -@S$S$%.%.FoF@F@7%S.tOtO5#^%tOz E i%)+6+a#b.[X}#p [Xv$MoMov@J%H+E$%#BO;XM@Bo+.+@ of r+lX-&ZOk%)@'o~$woI Y+PXY#,XY%<#B.3%ZoZoQ.8+h S$5#p$`..o3%Y#~$8.C+`#>.e%,@u+`$ ", +" r.y s+fO$%S#1Og#PXY%N$z#p@E#Fo#oxX@#F%5OMo..v$.@.@[Xp p }#}#}#v$E$3.5@I##o-@)$k#W@k$O$g+#oS$%.FoFoF@7%S.S.tO5#5#^%1X%+S.=$- IoK.7@4o..}#}#p [X.@Mo%#S GX:%8.|O8O8OM.M@BoM$ of O$r+-&k#(.)@'oq.u@I t$PXY#.+Y%<#3%<#k%`o1o8+yoS$^%E `.%@wO- 'o[XO k$e%Iod+T#-O ", +" J+D m%[%S%C+S#v@PXY%#.xXy., F@z )$W@5$$Xv@..v$v$.@.@[Xp }#}#p v$S C+i%t$B@w+hOfosO>.#.=$S$FoFoF@7%S.S.tO5#5#^%1X1XE#E#F@#ow$foBXF%[Op w+}#}#v$$XH+J#}#r@* I#|OU%8OM.<%Bo+.+@f f r+lXk#(.k%)@q.~$woI Y+- .+,XI 8O..]#ZXQOJ%^%Fo1Xp@FON$<#Y+(.4o5$$%fO5@A@<@V+ ", +" ooh@[%X 7@/O5Owo.+Zop+ OR+S.#o%+..hOH+v@Mo....v$.@[Xp p }#p .@$Xx$%%5.` fomX-oL@I$E#z F@7%S.S.tOtO5#5#^%1X%+E#E#, E#S$tOdXk@z@{+b.w+}#..J#H+5OfXW$H I+JX* I#|OU%8OM.<%Bo+.+@f f r+lXZO(.k%'oq.u@I PXt$f 8.4ovo/OS#3.QO6oF@F@E#y.,&#.Y%t$k#a#EoS%q#b RX[+ ", +" lO2#fOM i%@#0@(..+3%h z%p$5#-@Fo8OhOW@b.MoMo.....@[X[Xp }#}#[XMo4o@#rX$%;O1$)+B#b.%.#o7%S.tO5#5#^%1X1X%+E#, YXYXYXE##o O`X(XrXa#:%%#GX8$:%fX!@`o8.r@6oH w$JX* |O;XU%:#M.<%BoM$+@ of lX-&ZO(.'o~$ZO;X:%O&%%@##X#XS# &kok%S$S.YX Op+B@.+wo odXi%X [%8&e+& ", +" 3#&XG.Io6+F%] +@Y#B.%@FOyo1X%.-@- 1o] 5Ov@Mo.....@.@[Xp }#}#.@v@5Ob.b.[OcOI$H$1+r+g+%.tO5#^%^%1X%+%+E#, YXR+R+R+p$1Xz 'oq#q#rXx@8+5.J#:%..v$.@p p w+fX%&g#BOh%`o8.W$r@H w$I+* |O;X;X:#M.+.M$;XfX4o]Xx@%%c.@##X#XS#z@ZX$$S$5#p$'@h 3%Y#u@JXc.hO>oq#&OOo>$ ", +" ;#1 o.K.koS#%%I#PX<#N$z#)$E#7%#o`.]#5$$Xv@Mo....v$.@[X[X...@!@8OZOk# o|Ov$1OM k$$$=$S.^%1X1X%+E#E#, , YXR+p$p$E E S.#og#6&h$C#E@c.]Xe 8+8+dXO&a#cOcOW.f%/o5.5.E$0@S 8$8$H+# [O$X$XJ%%#[OS dX] vovovox@x@c.1OF%F%C+oXS , %.%+yo`..owOPXq.g#5$q Ioe%+o@&NX ", +" qO4 .6+@#{++.- <#%@FOp@%+Fo-@h ]X5$[OMoh%M@I <#B.wOY%,X.+- PXI 'o:#4o_+>ou@=$tO, , YXR+p$E E yoyop@p@)$y.y.%+=$YXJXg#Q.!@`o`o`o`o`o`o`o`o`o`o`o8.8.8.8.8.8.8.8.8.8.8.8.`o!@!@!@g#k$O%M+E@c.x$x$] vox@c.1OZXoX5.yoS$^%yo`.$$3%- u@I#x@r#>oq#{.[o.O ", +" _#~X[ fO$%ZX@#H Y+Y%#.,& OYXS.#oE#Q.3.}#)@wON$#.B@3%wOY%,X.+Y#PXI (.H 8+C#r#`.#o%+YXR+R+E E yoyop@)$)$y. O'@ OtO=$z -@-@-@-@-@-@-@-@-@-@-@-@-@-@-@-@-@-@S$S$S$S$S$S$S$S$S$S$S$-@-@ O`XO%QO7@x@x$x$x$] x@%%1Oi%$%:#FoFoE#)$z#.owOY+'o}#C+_+e%e%G$LXjO ", +" /@0$8#[%BXI$F%J#q.Y#3%$$z%E ^%S$%.wox$I+N$.o%@#.Zo3%B.<#Y%,XY#- I lXg#F%IoW@F@%.R+p$E E yoyop@)$)$y. O'@z%z%z%p$E#, , , YXYXYXYXR+p$R+p$p$E E E yoyop@p@)$)$y.y.y.y. O O O'@z%%+=$'oq#(XkoO ] {+{+x$] x@%%F%koO N$-@tOR+'@xX#.,XI O$5.7@O#q#M M%.rXF%]#BoPXwO%@z#)$E#F@#oy.5O0@- %@%@N$ZoB@3%wOY%,X,X- wo+@v@E@IoH #oS.E E p@p@p@)$y.y. O O'@z%`.FOFOFO,&,&xXxXp+$$$$h h %@%@N$N$#.ZoB@3%3%3%B.wOwO<#Y%Y%,X.+.+Y#Y#- p@z BOX#K.6+F%{+]X]X{+x$vox@V oXw+^%%.1Xyo`.h 3%- ~$I#%%hO1$q#POj%o+V+ ", +" &@6O$.fO$%S#@#h%wo,XZop+'@p$5#-@F@k#vo:#N$%@%@#.Zo3%wO<#Y%,X- u@M.H+` X Y%z %+p@p@)$y.y. O'@'@z%z%`.FOz#z#,&,&xXp+p+p+$$.o.o.o%@N$#.#.ZoZoB@3%B.wOwOwO<#Y%Y%,X.+.+Y#- - PX,X1X5#] C%M E@%%e e e {+x$voc.`XEo.+S$7%YXy.,&N$<#Y+)@MoC+_+e%e%Y$_%@@ ", +" `$[#A%[%BX3.F%0@k%Y#B..o`.p@%+Fo#o'@H+GX.+%@%@N$#.B@B.<#<#,X- 'oJXdXX 3.yo-@p$)$y.y. O'@z%z%`.`.FOz#,&xXxXxXp+p+$$h h .oN$N$N$#.ZoZoB@3%3%B.wOwO<#<#Y%,X,X.+.+Y#- PXPXY+t$B.Fo`.O#k@oX5$x$]#]#e {+x$voO S%..%+S$^%yoz%$$B@.+u@+@cOI$S%q#M c%@ -O ", +" OO'#+%K.P@q /O] ;XPXY%#.xX'@R+S.-@7%f x@8O#.N$N$#.Zo3%wO<#Y%- ZOh%F%P@GX%.F@)$y. O'@z%z%`.FOFOz#z#,&,&p+p+$$$$h .o.o%@N$#.#.ZoB@B@B@3%wOwOwO<#Y%Y%,X.+Y#Y#Y#- PXY+Y+Y+I wop+-@lX)#)#` #Xe 8+8+]#]X] voi%3.- -@7%, y.z#%@wOPXq.r@#X &5@q#N%w.s. ", +" `OA#i [%oXV #Xb.~$.+3%h FOyo%+Fo#o O[O5.wo#.N$#.ZoB@B.wO,XPXO$v@rXq#U%=$1Xz%'@z%`.`.FOFOz#,&xXxXxXp+$$h .o.o%@N$N$N$#.ZoZoB@3%B.B.wO<#<#<#Y%.+.+Y#Y#- PX- PXt$t$I I wowop@S$:%C%Io &%%8+dX8+]#cO5OMo#Xw+%+%.^%E z%$$B@,XI -&8$7@z@fO>.L+e$iO ", +" ]Oio^Xq#5@ &/Ox$M@PXY%#.xX OYXtO-@%.'ovoQ.wON$N$#.B@B.B.,Xk#w+5$[%5@B@#op$`.`.`.FOz#z#,&xXxXp+$$$$h .o%@%@N$N$#.ZoZoB@3%3%B.wOwO<#<#Y%,X.+.+Y#Y#- PXY+Y+Y+t$I wowou@~$PX1X, O X#M+I$x$dXa#8$g#-&wo..8+B@-@7%, y.z#%@wO- u@JX1OhOM+q#C#>@-.OO ", +" V+2++XF$fOl.C+#Xv$u@Y#B..o`.p@%+F@#op$w+x$r+#.N$N$#.wO(.h%W@1oQOk@U.p$S$)$`.`.`.FOz#z#,&xXp+$$$$h h .o.o%@%@N$#.#.ZoB@B@3%B.B.wOwOY%Y%,X,X.+Y#Y#- - PXPXY+t$t$I wou@u@wO%.N$M+) ;OZXO&5O|Owo%@.oM@x@|OS.%.1XE z%p+B@.+I (.J#1o` P@P@e@O+3+ ", +" ~%n#7O[%>o  M$Y+Y%N$xX Op$^%%.-@wOO&J#PXN$.+M$.@O&@#C+ &>oX## %.z 7%tOtOtOtOtOtO^%^%^%^%^%^%^%1X1X%+%+%+%+%+%+%+E#E#E#E#, , YXYXYXYXYXYXYXYXR+R+p$p$p$p$E E E E 1X#oM$)+0X &S M@<#xXxX$$u@/oGXz%-@tOYXy.,&%@<#PXu@;X%%hOBXq#M+&.>XG+ ", +" n.C *.fOO#5$#Xv$~$Y#B.%@FO)$YXtO#o5# o1O:%`oS vo#X#X#XV `XK.h$I#S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.7%S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.%+8$j.z@H+O$B@p+xX$$<#..]XY+Fo7%E#p@`.h B@.+I (.J%V ` e%e%6.R#0+ ", +" b#VX3Oq#5@6+S#{+8Ot$Y%Zop+`.p@E#Fo#oR+!@k$rXO /O#X#X/O7@z@0X) 5$]#e e e e e e e e e e e e e e e e ]Xe 8+8+8+8+8+8+8+8+]#8+8+8+8+8+]#]#]#]#]#8+8+]#]#e e ]#]#e ]#]#]#]#oXIo1O!@q.B@h p+#.w$x@+.S.Fo1XE '@xX#.<#PXq.I+c.hOBXq#M+S@/ G+ ", +" o ;+9o$.q#oX7@#X# (.- <#N$,&'@p$5#S$-@z#5.M+i%S##X#XO 3.koP@O%EO6&6&6&6&6&6&6&B#6&B#B#B#EOB#EOEOX#O%fofofofok@fok@k@k@O%O%j.j.j.j.j.$O$O$OX#X#X#X#C%X#X#C%.X.XX#O%) (XIorXE$;Xt$3%N$N$f ]Xw+R+-@tOR+y.z#.oB.Y#woO$0@7@z@K.P@t@{#&@o ", +" NXpo{@q#Ioq /Oc.W$wo.+B@h z#y., S.-@%.Y#/OX 3./O#XS#V rXoX5@P@e%P@e%P@P@IoIoIo>.H$>.H$5@X $%q 6+rX6+6+`#`X`X`X_+_+k$` ` kokoz@z@l.;O;O;OO#S%S%S%oXQOX BXoXkoq rXr#i%C+cOg#O$- B.3%ZO5.GXp+-@7%E#)$z#$$B@,Xt$)@w+/O &>o[%BXa%b$/@ ", +" V+s.,#}+[%X Eo/OcO oPX<##.p+`.E %+7%#oS.(.1ooX7@#X#XZX1ohO6+`#`#6+6+rX &r#r#hOhOU.1o%%/o# J%$X[O# H+H+8$4o0@E$5./oW@f%cOcOO&dX8+]#e ]X{+x$] x@c.#X#Xx@a#5.S H+# $X5Ov$W$M$~$- <#k#4o/o<#%.F@1XE '@p+N$wO- u@8O]XE@O#fO>.Z ^#L%o ", +" 4OioW#e%K.z@5$/O:%)@- <##.p+'@E %+F@#o5#O$I$S%7@/O/O/OO O ZXO /O#XF%@#1Oc.x$5.w+* +.+.Bo<%8O:#;XI#* I+w$H r@8.`oh%Q.g#%&w+}#[X.@v$Mo:%b.[O8$S %#}#Q.8.W$H I+I#U%8O+.r+'ot$PXlX4oO&Y+FoFo1Xp$ O,&%@B.Y#I lX# 1o_+>.q#XX*+:O8 ", +" +:+&#q#5@q O %%8.u@- wON$z# Op$1XF@#o%+M$EoO#7@/OF%@#1Oc.%%x@vo] ]XE$}#8Oq.Y+I u@q.)@(.k#-&r+f +@+.Bo<%M.:#;X|O* JXw$H 6o8.`oh%%&.@5Ob.p !@6ow$* ;X:#<%Bo+@O$-&(.'ou@woM$5.]#q.7%%.^%R+y.FO.o3%.+t$)@}#S# &M+[%M o&U#9$ ", +" J+X@,$A$[%X i%/O]#M.t$.+3%h z#y.R+^%Fo#oE# oV S%3.F%@#1Oc.%%vodX%#* 'o,XY%,X.+- Y+wou@q.)@(.k#lXO$f oM$Bo<%8O:#;XI#* I+w$r@Q...5O5Op g#`oW$6oI+I#U%8OM@M$ or+k#k%)@)@U%W.8+q.tOS$tOYXy.FO$$ZoY%Y+q.JXvoE@O#q#P@t@;.S+V+ ", +" NX+#T+K.K.;O7@#XH+-&Y+,XZoh FOy.YX5#%.#o^%k#S#oXU./O@#] E$BOlX<#N$#.3%wOY%,XY#- t$wo~$'ok%(.k#lXO$f oM$M@<%M.:#;XI#w$BOMoJ#5O..}#%&BO!@8.6oI+* ;X:#<%+. oO$lXk#lXr@e f%Y+7%%.5#, )$`.$$#.<#PX~$Bof%I$koP@q#QOC$/ /@ ", +" V+g.|%>#q#Ioko5$F%v@k%PX<##.$$FO)$YX^%Fo#oS.u@x$oXi%H+|OPXh p+$$%@N$B@B.<#Y%.+- PXI u@q.)@k%ZO-&r+O$f +@BoM@<%:#H }#$XGX[Ob.Mo.@p w+g#h%`or@w$JX|OU%M.Bo+@f f M@Mo@#S <#Fo%.tO, p@`.p+#.<#- u@O$J#5$q 5@[%;$G#%o`O ", +" OO6#dO2 [%H$q ZX1O}#)@- <##.h FOy.p$^%F@#oFoB@5O5$..Y+.op+p+$$.oN$Zo3%<#Y%.+Y#PXt$woq.)@k%(.k#lXO$f o+.8O8.Mo8$0@GX[O%#b.v@..[X}#%&BO!@W$H I+I#;X8O<%BoBoH W@/Ow+p+%.Fo5#, p@`.p+#.wOY#wolX:%O &M+[%5@3$0&~.V+ ", +" /@)X7.2@[%1$ &O %%Q.q.- <#Zoh z#y.p$1X7%-@S$y.I#] 8$M$B.h h .o%@ZoB@wOY%,XY#- t$wo~$'o)@k%k#-&r+ oU%Q.J#/oW@0@8$GXJ#J%5Ov@...@p fXg#h%8.r@H JX|OU%:#* ..c.vo+.R+-@Fo1XR+)$`.p+#.wOY#I ZO.@S#U.QOq#P@^$++@%-O ", +" 9$eX~#Doq#X i%S#x$w$wo- <#Zoh z#y.E E#S.S$#o%+(.5.] w+~$N$%@%@ZoB@B.<#,X.+- PXI u@q.'o)@(.O$|Ov$5.dXcOf%/oE$4oH+# [O%#:%Mov$p w+g#Q.`oW$6oI+* JXw+dXV 8$Y+S.S$7%^%R+y.`.p+N$wO.+wok%%&F%i%O#K.K.;Of$1%^+ ", +" V+SXXO3@e%fOQOi%S#e I#wo- <#Zoh z#'@yo, tO%.#o7%.oW$x$cOI#PXZoZoB@B.wOY%,XY#PXt$wou@'of r@$XdX]Xe 8+a#W./o5.0@8$GXJ#$X5Ov@Mo.@p fXBOh%8.W$r@fX5.5$] ;X`.%.%.7%E#p$ OFO$$#.wOY#I k%!@1Oi%;OP@fOC#H.m s% ", +" $ ~+/Xu%K.fOQOi%S#]#H q.PX<#B@.oxXz%p@R+1X7%-@z 1XY+b.%%5.w$~$<#B.wOY%.+.+Y#- ~$Bo}#f%voc.vo{+e 8+O&cOf%/o0@S H+# [O%#:%v@..[Xw+%&BOg#Moa#V S#}#B@S.#oF@5#, yo'@,&h ZowO- woZO%&1Oi%l.P@q#BX>+|$g$o ", +" OO<$G@gOK.fOoXi%S#] h%'oPXY%3%N$xX`. OE E#tOFo-@S$E k%J%%%O&BOf t$Y#,X- )@* [O{+/O/O@#%%vox$]X]#dXa#f%W@5.4oS GX[OJ%b.v@...@.@v@H+] I$S#..PX%+-@%.S.%+p$)$`.xX%@3%Y%- wo-&[X#Xi%;Oe%q#BX>+7#z+o ", +" OOpX_@gOK.fOQOU.O c.}#k%Y+.+wO#.h ,&'@p@YX%+S.%.#oS$yoq...vovoH+W$I#}#f%1OS#S#/O#XF%c.x@] x$e 8+O&W.f%/o0@S H+J#[OJ%%#[O0@]X1oE@c.fX.+E#-@S$7%1XYXyo OFO$$N$3%,XY+u@f b.O U.;Oe%q#BX7Xx#Z#8 ", +" s j$*#p#K.fOC#r#ZX@#v@-&t$- <#B@%@xX`. OE , ^%7%%.-@%.YXY%w$E$S#`XS%z@r#I$C+O /O#X@#c.x@vox$]X8+O&cOW@5.0@0@E$f%e #XEor#5$4oU%N$1X-@%.F@^%E#E y.z%,&.oZo<#Y#t$q.+.# ZXr#S%e%q#X 7X{O*X-O ", +" qOxoo#p#K.q#M+`#V #X8$M.woPX,XB.#.$$,&'@)$E YX^%7%%.#o-@S.z%~$`of%V l.QOQO;O` 6+U.3.1oZXS##XF%F%F%#XO 1oU. &6+r#@#S w$PXp@F@-@S$7%^%E#p$)$'@z#p+N$B.Y%- wo)@* f%V rXQOK.fOX 4+m#o` I$O ]X`ok%t$- Y%B@%@p+z#z%y.E , 1XtOFo-@#o-@S.E #.-&`oJ#]XC+rXko;OS%S%O#;Ol.z@ko6+7@@#8+J%H (..oR+F@-@-@FoS.^%E#p$)$'@z#p+.oZowOY#Y+wo-&}#x@I$`X1$q#K.oX`%D.S+-O ", +" 8 KX7$u *.[%P@;OU.C+1O5OM$~$PX,XwOZo%@$$z#z%y.yoR+E#5#S.FoS$-@z S$7%%+p@.oY#'olXBo;XI+I+;XM$-&q.Y%p+E 1XF@-@#oS$%.7%5#%+YXyo)$'@FOp+.oZowO,XPXwo'oM.# S#U.z@H$q#>.;OH.]$&@8 ", +" OOho>%8X;$[%K.C#`#1oS#O&!@k#t$- ,XB.Zo%@$$,&FO'@)$p$YXE#^%tOF@FoS$-@#o#o#o#o-@%.FoFoF@Fo%.-@-@#o-@-@-@%.F@tO^%%+YXp$p@ O`.z#p+.oZoB.Y%- I ~$r+%&e 1orXoXP@[%>o[$_X%oF.V+ ", +" OO& h#|+'%e%q#5@$%E@C+@#H+;Xq.Y+- ,XwOB@%@h p+FOz% O)$E R+, %+1X5#tO7%F@F@F@Fo%.%.%.FoF@F@7%S.tO5#^%%+, R+E p@y.z%FO,&$$%@Zo3%Y%Y#t$wo(.I+0@/Oi%k$1$q#fOBXN+9XZ.s%o ", +" V+P )X_.2%$.[%K.X q 3.ZXx$v@<%q.Y+- ,XwOB@#.%@$$xXFOz%'@y.p@yop$p$YX, E#%+%+%+%+%+%+%+E#YXYXR+p$E p@y. Oz%FOz#p+.oN$ZowO,XY#Y+u@k%U%J%c.I$6+oXP@[%IoS%P%H#xoiO ", +" /@w#[.~OcXe%q#>.oX6+I$O {+b.:#k%I PXY#Y%wO3%Zo%@$$p+xXz#FOz%'@'@y.)$)$)$)$)$)$)$)$)$y. O'@z%`.z#xXp+h %@N$B@B.Y%.+PXt$u@k#* [O%%7@rXl.5@q#fOM+0o|X-$;&-O ", +" OOHoe.D%| M fOq#H$O#6+I$O ] $X* lXu@I PXY#,X<#B.3%ZoN$.oh $$p+xXxX,&z#z#,&,&,&,&xXxXp+$$h .oN$#.B@B.wOY%.+- t$u@)@ o6oS @#I$ &$%M fOq#H$&OzO;.Q+`OV+ ", +" o b#f@!$7.pOH$q#q#H$O#6+3.C+1O5.}#8Ok#u@t$PX- .+,X<#B.B.B@Zo#.#.#.N$N$N$N$#.#.#.#.B@3%B.wO<#Y%.+Y#PXI woq.r+|O..a##X3.rX$%M fOq#IoQODX4X; A /@ ", +" V+,o)XN ^Oc#>.q#q#H$oX`Xi%V O ] H+g#U%-&'oI t$Y+PX- Y#,X,X,XY%<#<#<#<#<#Y%Y%,X.+Y#Y#- PXt$I u@k%O$I#}#5.c.V E@`#O#>oK.[%e%X F K$]%m.4#V+ ", +" 9 xO*Ox.CXSOH$q#q#P@BX$%6+E@V ZX] dX%#h%;Xr+(.)@~$woI t$Y+Y+t$t$Y+t$t$Y+t$I woq.k%ZOO$* g#J#]#%%1oEorXkoX >.q#q#IoX e@:.{#b$O@8 ", +" o qOsX~@i@}.`@1$e%[%fO>.BX$%`#U.3.5$5$x@a#a#8$}#8.6ow$* U%<%M$M$M.;XJXH r@8.[X4oa#dXc.7@I$U.q $%C#H$K.[%K.>oS%q$C$=+(+1#^. ", +" o 4O1@w@s$n@,@V#H$fO[%q#P@M oXz@q &U.E@V C+5$5$ZX@#] e dXdX]XvoF%ZX5$5$V 3.hO &q koS%1$IofO[%fOIoX %'Ox W%% *%4Oo ", +" 4OQ#Q%t.VO}O9.8&5@K.q#[%q#P@>oBXoXl.` `X6+rXr#U.U.U.U.U.hO &6+q k$$%S%X >oIofO[%q#fO>.BX@OD+/$toY Uo3+G+ ", +" 8 ' ;+L$H#=&=Xt@WO1$H$e%q#[%[%q#K.P@>.H$5@>oM M >o>o5@H$>.P@K.fOq#[%q#K.>.1$WOd.MXk.{ow%@ s.iOOO ", +" G+J.Ko{ qo>O @/#2o&OWOM+>oH$P@e%fOq#q#[%q#q#q#q#q#K.Io>.>oM+C#O#jo2&9%IO($: T$EX@@-O ", +" o 8 @@g.z$uO7+;.#&nXR@vXB _ koz@$%$%l.l.$%z@` k$d$x+v#R$ $DOa bOZ.B+k jOOOV+ ", +" o f+=%P$0.To^@UXU#7 aoA.l#P+,O=OF+nONoQ k+jXUX^@v.T >$NXf+o ", +" OO-O~%p.j@}$.%Z%'$'$f.! oOu.*&s -OOO ", +" " +}; diff --git a/share/pixmaps/bitcoin16.png b/share/pixmaps/bitcoin16.png new file mode 100644 index 0000000000000000000000000000000000000000..540fab05f5450996a32ac84ef7cefb43b4305307 GIT binary patch literal 871 zcmV-t1DO1YP)Gq~b8`06b{1=EYoJ09 zeP*KYcsviXv$Mad$&jawjg3Y|SzKHcW2ifb5pr^JFh4(!WHO1?)>bhtkw^#t$*m0r zgLWk$S}hg}%YaU&LqS1-7*|$SCJo4W6c!eO=wfws6>hg1)6>(atE*#wtZM3B!#@=j z6`{PmT(tA5s;UwXXq>``D9e*2FbI1?OiVn5lv1hWDPU)3M>5gV(}S$6EP0=pm=HN! z(9+T(%-GO-DR)ZRkytDS-rR`I+uhw28JnA%a>iS&R%35(52K@_2!%qRurbk~ibA8I z;%9AbZK9bAX~yzo7Ob_RqC$|DmzS};dTICynvd;NW12=go5XoB}2?%w{vJR;x^4U|=9YO<$6vNzR9= ztE)>8C{VtGgM$UH*IPp_8yJc6!Auz4=ksv}7RZ|yG)6a}i=_Xzkxe5hzsMNx%*@Oa xiti)3nI`&lM-BNp|EBLADvtAY{ c #F9F9F9", +", c None", +"< c None", +"1 c #A2A2A2", +"2 c #C4C4C4", +"3 c #707070", +"4 c #707070", +"5 c #9E9E9E", +"6 c #8F8F8F", +"7 c #B1B1B1", +"8 c #D3D3D3", +"9 c #686868", +"0 c #686868", +"q c #6C6C6C", +"w c #C0C0C0", +"e c #9E9E9E", +"r c #C0C0C0", +"t c #9A9A9A", +"y c None", +"u c #5C5C5C", +"i c #8B8B8B", +"p c #ADADAD", +"a c #CFCFCF", +"s c #9A9A9A", +"d c #BCBCBC", +"f c None", +"g c #969696", +"h c #878787", +"j c #A9A9A9", +"k c #CBCBCB", +"l c #969696", +"z c #B8B8B8", +"x c #B8B8B8", +"c c #DADADA", +"v c #C7C7C7", +"b c #E9E9E9", +"n c #A1A1A1", +"m c #929292", +"M c None", +"N c #B4B4B4", +"B c None", +"V c None", +"C c #7F7F7F", +"Z c #A1A1A1", +"A c None", +"S c #8A8A8A", +"D c #C3C3C3", +"F c #8A8A8A", +"G c None", +"H c #9D9D9D", +"J c #8E8E8E", +"K c None", +"L c #B0B0B0", +"P c #5F5F5F", +"I c #5F5F5F", +"U c #BFBFBF", +"Y c #BFBFBF", +"T c None", +"R c #5B5B5B", +"E c #CECECE", +"W c #999999", +"Q c #DDDDDD", +"! c None", +"~ c #868686", +"^ c #A8A8A8", +"/ c #CACACA", +"( c #737373", +") c #959595", +"_ c #B7B7B7", +"` c #B7B7B7", +"' c None", +"] c #828282", +"[ c #A4A4A4", +"{ c #C6C6C6", +"} c #A0A0A0", +"| c #919191", +" . c None", +".. c #B3B3B3", +"X. c None", +"o. c #6A6A6A", +"O. c #A0A0A0", +"+. c #6E6E6E", +"@. c #C2C2C2", +"#. c #6E6E6E", +"$. c #898989", +"%. c None", +"&. c #8D8D8D", +"*. c #AFAFAF", +"=. c #D1D1D1", +"-. c #F3F3F3", +";. c #5E5E5E", +":. c #5E5E5E", +">. c #BEBEBE", +",. c #9C9C9C", +"<. c #858585", +"1. c #989898", +"2. c #898989", +"3. c #EFEFEF", +"4. c #989898", +"5. c #A7A7A7", +"6. c None", +"7. c #C9C9C9", +"8. c #EBEBEB", +"9. c #909090", +"0. c #949494", +"q. c #B6B6B6", +"w. c #B6B6B6", +"e. c #D8D8D8", +"r. c #818181", +"t. c #A3A3A3", +"y. c #C5C5C5", +"u. c #B2B2B2", +"i. c None", +"p. c #D4D4D4", +"a. c None", +"s. c None", +"d. c #7D7D7D", +"f. c #9F9F9F", +"g. c #C1C1C1", +"h. c #E3E3E3", +"j. c None", +"k. c #656565", +"l. c None", +"z. c #AEAEAE", +"x. c #656565", +"c. c #BDBDBD", +"v. c #9B9B9B", +"b. c #BDBDBD", +/* pixels */ +" G y A I o.0 :.< # G ", +" 6.V = n w / 7.>.5 4 X.6. ", +" 6.s.9.o 7.j | 6 ..8 / F K 6. ", +"G V * p.d 1 ~ | l s u.^ o F X.G ", +"' = o r z.t.e 7.@.] C C ; & #.f ", +", } & f.t.s N e.x $ 5.@.v E t X.", +"P U N ^ 7 ,.a b b.0.w.5.. O.z u ", +"9 / v { X Z 8.-.g.2.. r.&.p 2 x.", +"9 / ` 1 ) @ > Q h J 4.*.2 2 2 k.", +";.c.L 1 4.7.3.y.~ - ,.W i % q.R ", +"V H =.{ X p.h.c o 7.v - d.r g a.", +"# 3 7.u.( 0.t.t.e W v.s g.2 q %.", +"G : S k j ..+ [ | m 1 Y E <. .! ", +" M l.$.& 8 x ) O z.7.2 <.j.i. ", +" i.a.+.1.z D D _ g q .i. ", +" G T B u x.x.R a.T G " +}; diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png new file mode 100644 index 0000000000000000000000000000000000000000..0f772ed37b6d39be70ea4698cebdc0fb2e677cca GIT binary patch literal 50148 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 M07*qoM6N<$g8OQz4gdfE literal 0 HcmV?d00001 diff --git a/share/pixmaps/bitcoin256.xpm b/share/pixmaps/bitcoin256.xpm new file mode 100644 index 0000000..ac3a979 --- /dev/null +++ b/share/pixmaps/bitcoin256.xpm @@ -0,0 +1,1969 @@ +/* XPM */ +static char *graphic[] = { +/* width height num_colors chars_per_pixel */ +"256 256 1706 2", +/* colors */ +" c None", +". c #444444", +"X c None", +"o c None", +"O c #5E5E5E", +"+ c #656565", +"@ c #8E8E8E", +"# c #5D5D5D", +"$ c None", +"% c #666666", +"& c #565656", +"* c #7F7F7F", +"= c None", +"- c #5D5D5D", +"; c #888888", +": c #4F4F4F", +"> c None", +", c #AAAAAA", +"< c #777777", +"1 c None", +"2 c #707070", +"3 c None", +"4 c #535353", +"5 c None", +"6 c #CCCCCC", +"7 c #313131", +"8 c None", +"9 c None", +"0 c #787878", +"q c None", +"w c #535353", +"e c None", +"r c #EEEEEE", +"t c None", +"y c #616161", +"u c None", +"i c #7F7F7F", +"p c #5A5A5A", +"a c #0F0F0F", +"s c #4B4B4B", +"d c None", +"f c #8A8A8A", +"g c None", +"h c None", +"j c #313131", +"k c None", +"l c #535353", +"z c #696969", +"x c #616161", +"c c None", +"v c None", +"b c #535353", +"n c None", +"m c None", +"M c #5A5A5A", +"N c None", +"B c #5E5E5E", +"V c #757575", +"C c #4F4F4F", +"Z c None", +"A c None", +"S c #686868", +"D c None", +"F c None", +"G c #5D5D5D", +"H c #979797", +"J c #6D6D6D", +"K c None", +"L c #656565", +"P c #7F7F7F", +"I c None", +"U c #B9B9B9", +"Y c None", +"T c #7B7B7B", +"R c None", +"E c #5A5A5A", +"W c #DBDBDB", +"Q c None", +"! c None", +"~ c #4F4F4F", +"^ c #868686", +"/ c None", +"( c #616161", +") c None", +"_ c None", +"` c None", +"' c #FDFDFD", +"] c #616161", +"[ c #686868", +"{ c #525252", +"} c None", +"| c #7B7B7B", +" . c #5D5D5D", +".. c #565656", +"X. c None", +"o. c None", +"O. c None", +"+. c #1E1E1E", +"@. c None", +"#. c None", +"$. c None", +"%. c #404040", +"&. c #4F4F4F", +"*. c #404040", +"=. c None", +"-. c #626262", +";. c None", +":. c #4B4B4B", +">. c #777777", +",. c #626262", +"<. c #4F4F4F", +"1. c #686868", +"2. c None", +"3. c None", +"4. c #525252", +"5. c #5D5D5D", +"6. c None", +"7. c #646464", +"8. c #6D6D6D", +"9. c None", +"0. c #848484", +"q. c #4F4F4F", +"w. c #4B4B4B", +"e. c None", +"r. c None", +"t. c None", +"y. c None", +"u. c #A6A6A6", +"i. c None", +"p. c None", +"a. c #525252", +"s. c #C8C8C8", +"d. c None", +"f. c #474747", +"g. c #8A8A8A", +"h. c None", +"j. c #696969", +"k. c #6C6C6C", +"l. c #EAEAEA", +"z. c None", +"x. c #616161", +"c. c None", +"v. c #4F4F4F", +"b. c None", +"n. c None", +"m. c #565656", +"M. c #0B0B0B", +"N. c #656565", +"B. c #4F4F4F", +"V. c #646464", +"C. c #2D2D2D", +"Z. c #5E5E5E", +"A. c #4F4F4F", +"S. c #5A5A5A", +"D. c None", +"F. c #4F4F4F", +"G. c #707070", +"H. c None", +"J. c #5A5A5A", +"K. c None", +"L. c #717171", +"P. c None", +"I. c #646464", +"U. c #595959", +"Y. c None", +"T. c None", +"R. c None", +"E. c #939393", +"W. c None", +"Q. c None", +"!. c #616161", +"~. c None", +"^. c None", +"/. c #686868", +"(. c #B5B5B5", +"). c None", +"_. c #4A4A4A", +"`. c None", +"'. c None", +"]. c #646464", +"[. c #606060", +"{. c #D7D7D7", +"}. c None", +"|. c None", +" X c None", +".X c #5D5D5D", +"XX c #7B7B7B", +"oX c #565656", +"OX c #525252", +"+X c #F9F9F9", +"@X c None", +"#X c #656565", +"$X c None", +"%X c None", +"&X c None", +"*X c #525252", +"=X c #1A1A1A", +"-X c None", +";X c #555555", +":X c #5E5E5E", +">X c None", +",X c #3C3C3C", +"o c None", +",o c None", +"O c #525252", +",O c None", +"+ c #CBCBCB", +",+ c None", +"<+ c None", +"1+ c #525252", +"2+ c None", +"3+ c None", +"4+ c None", +"5+ c #5C5C5C", +"6+ c None", +"7+ c #EDEDED", +"8+ c #595959", +"9+ c #4E4E4E", +"0+ c #3F3F3F", +"q+ c None", +"w+ c #767676", +"e+ c #555555", +"r+ c None", +"t+ c #0E0E0E", +"y+ c #303030", +"u+ c None", +"i+ c None", +"p+ c #525252", +"a+ c None", +"s+ c None", +"d+ c None", +"f+ c #525252", +"g+ c #5D5D5D", +"h+ c None", +"j+ c None", +"k+ c #7E7E7E", +"l+ c None", +"z+ c None", +"x+ c None", +"c+ c #747474", +"v+ c #555555", +"b+ c #4A4A4A", +"n+ c #3F3F3F", +"m+ c #606060", +"M+ c #969696", +"N+ c #676767", +"B+ c None", +"V+ c #B8B8B8", +"C+ c None", +"Z+ c #606060", +"A+ c None", +"S+ c #4E4E4E", +"D+ c #DADADA", +"F+ c None", +"G+ c #4E4E4E", +"H+ c None", +"J+ c #555555", +"K+ c #515151", +"L+ c #5C5C5C", +"P+ c None", +"I+ c #FCFCFC", +"U+ c None", +"Y+ c None", +"T+ c None", +"R+ c #3F3F3F", +"E+ c #1D1D1D", +"W+ c #4E4E4E", +"Q+ c None", +"!+ c #3F3F3F", +"~+ c None", +"^+ c None", +"/+ c None", +"(+ c #676767", +")+ c #4E4E4E", +"_+ c #7A7A7A", +"`+ c #616161", +"'+ c #4E4E4E", +"]+ c #595959", +"[+ c #6B6B6B", +"{+ c #5D5D5D", +"}+ c None", +"|+ c #595959", +" @ c #838383", +".@ c #606060", +"X@ c None", +"o@ c #585858", +"O@ c None", +"+@ c None", +"@@ c #A5A5A5", +"#@ c None", +"$@ c None", +"%@ c None", +"&@ c #585858", +"*@ c None", +"=@ c #4E4E4E", +"-@ c #7A7A7A", +";@ c None", +":@ c #5C5C5C", +">@ c #898989", +",@ c #6C6C6C", +"<@ c #C7C7C7", +"1@ c None", +"2@ c #595959", +"3@ c #4E4E4E", +"4@ c #6C6C6C", +"5@ c #5D5D5D", +"6@ c #E9E9E9", +"7@ c None", +"8@ c None", +"9@ c None", +"0@ c None", +"q@ c None", +"w@ c #0A0A0A", +"e@ c #686868", +"r@ c None", +"t@ c None", +"y@ c None", +"u@ c #2C2C2C", +"i@ c #5D5D5D", +"p@ c None", +"a@ c #646464", +"s@ c #4E4E4E", +"d@ c None", +"f@ c #5C5C5C", +"g@ c None", +"h@ c #707070", +"j@ c #585858", +"k@ c None", +"l@ c None", +"z@ c #929292", +"x@ c #7A7A7A", +"c@ c None", +"v@ c None", +"b@ c #B4B4B4", +"n@ c #4A4A4A", +"m@ c None", +"M@ c #767676", +"N@ c None", +"B@ c None", +"V@ c #D6D6D6", +"C@ c None", +"Z@ c #7A7A7A", +"A@ c #676767", +"S@ c None", +"D@ c #767676", +"F@ c #595959", +"G@ c #F8F8F8", +"H@ c #545454", +"J@ c #5D5D5D", +"K@ c None", +"L@ c #636363", +"P@ c None", +"I@ c None", +"U@ c None", +"Y@ c None", +"T@ c #191919", +"R@ c None", +"E@ c None", +"W@ c #5D5D5D", +"Q@ c #3B3B3B", +"!@ c None", +"~@ c #606060", +"^@ c None", +"/@ c #4D4D4D", +"(@ c #727272", +")@ c None", +"_@ c None", +"`@ c #4A4A4A", +"'@ c None", +"]@ c #5D5D5D", +"[@ c None", +"{@ c None", +"}@ c #545454", +"|@ c #636363", +" # c None", +".# c #7F7F7F", +"X# c None", +"o# c #585858", +"O# c #4A4A4A", +"+# c None", +"@# c None", +"## c #464646", +"$# c #A1A1A1", +"%# c #4A4A4A", +"&# c #727272", +"*# c #636363", +"=# c None", +"-# c #5F5F5F", +";# c None", +":# c #C3C3C3", +"># c #5C5C5C", +",# c #737373", +"<# c #595959", +"1# c #606060", +"2# c #E5E5E5", +"3# c #4A4A4A", +"4# c #585858", +"5# c None", +"6# c #727272", +"7# c #5C5C5C", +"8# c None", +"9# c #6E6E6E", +"0# c #5F5F5F", +"q# c #636363", +"w# c #595959", +"e# c None", +"r# c #060606", +"t# c #A3A3A3", +"y# c #4A4A4A", +"u# c None", +"i# c #515151", +"p# c #282828", +"a# c #4A4A4A", +"s# c None", +"d# c #909090", +"f# c #5F5F5F", +"g# c None", +"h# c None", +"j# c None", +"k# c None", +"l# c #858585", +"z# c #555555", +"x# c None", +"c# c #6C6C6C", +"v# c #636363", +"b# c #595959", +"n# c #8E8E8E", +"m# c #5C5C5C", +"M# c None", +"N# c None", +"B# c #595959", +"V# c #464646", +"C# c #858585", +"Z# c None", +"A# c #B0B0B0", +"S# c None", +"D# c #5F5F5F", +"F# c #636363", +"G# c #D2D2D2", +"H# c None", +"J# c #595959", +"K# c None", +"L# c #545454", +"P# c #F4F4F4", +"I# c #515151", +"U# c #494949", +"Y# c None", +"T# c #595959", +"R# c #464646", +"E# c None", +"W# c None", +"Q# c #606060", +"!# c #464646", +"~# c #151515", +"^# c None", +"/# c None", +"(# c #515151", +")# c None", +"_# c #373737", +"`# c None", +"'# c #5C5C5C", +"]# c None", +"[# c #595959", +"{# c None", +"}# c #595959", +"|# c None", +" $ c #555555", +".$ c #5F5F5F", +"X$ c #585858", +"o$ c #606060", +"O$ c #636363", +"+$ c #7B7B7B", +"@$ c None", +"#$ c #4D4D4D", +"$$ c None", +"%$ c None", +"&$ c #464646", +"*$ c #5F5F5F", +"=$ c None", +"-$ c None", +";$ c None", +":$ c None", +">$ c #9D9D9D", +",$ c None", +"<$ c #727272", +"1$ c None", +"2$ c None", +"3$ c None", +"4$ c None", +"5$ c #BFBFBF", +"6$ c None", +"7$ c None", +"8$ c #494949", +"9$ c #636363", +"0$ c None", +"q$ c None", +"w$ c #585858", +"e$ c #646464", +"r$ c None", +"t$ c #E1E1E1", +"y$ c #4D4D4D", +"u$ c None", +"i$ c #555555", +"p$ c #5C5C5C", +"a$ c #6B6B6B", +"s$ c None", +"d$ c None", +"f$ c #464646", +"g$ c #636363", +"h$ c #6F6F6F", +"j$ c #545454", +"k$ c None", +"l$ c #242424", +"z$ c None", +"x$ c None", +"c$ c #737373", +"v$ c None", +"b$ c #585858", +"n$ c None", +"m$ c None", +"M$ c #464646", +"N$ c None", +"B$ c #4D4D4D", +"V$ c None", +"C$ c None", +"Z$ c #686868", +"A$ c None", +"S$ c None", +"D$ c #555555", +"F$ c None", +"G$ c None", +"H$ c #8A8A8A", +"J$ c None", +"K$ c #646464", +"L$ c #5F5F5F", +"P$ c #6E6E6E", +"I$ c None", +"U$ c #585858", +"Y$ c None", +"T$ c #8C8C8C", +"R$ c None", +"E$ c #494949", +"W$ c None", +"Q$ c #ACACAC", +"!$ c #585858", +"~$ c None", +"^$ c #6A6A6A", +"/$ c #555555", +"($ c #515151", +")$ c #CECECE", +"_$ c None", +"`$ c None", +"'$ c #6E6E6E", +"]$ c #5F5F5F", +"[$ c #555555", +"{$ c None", +"}$ c None", +"|$ c #F0F0F0", +" % c #585858", +".% c None", +"X% c #606060", +"o% c None", +"O% c #6A6A6A", +"+% c None", +"@% c None", +"#% c #111111", +"$% c #676767", +"%% c None", +"&% c None", +"*% c #555555", +"=% c None", +"-% c #333333", +";% c None", +":% c #4D4D4D", +">% c #6E6E6E", +",% c #555555", +"<% c None", +"1% c #5F5F5F", +"2% c #6F6F6F", +"3% c #555555", +"4% c None", +"5% c None", +"6% c None", +"7% c None", +"8% c #424242", +"9% c #777777", +"0% c #515151", +"q% c None", +"w% c #9B9B9B", +"e% c None", +"r% c #797979", +"t% c #6E6E6E", +"y% c #999999", +"u% c None", +"i% c None", +"p% c None", +"a% c None", +"s% c #545454", +"d% c #BBBBBB", +"f% c #585858", +"g% c None", +"h% c #727272", +"j% c #6B6B6B", +"k% c None", +"l% c #5B5B5B", +"z% c #DDDDDD", +"x% c #515151", +"c% c #5C5C5C", +"v% c None", +"b% c None", +"n% c None", +"m% c #FFFFFF", +"M% c None", +"N% c None", +"B% c None", +"V% c #646464", +"C% c None", +"Z% c #4D4D4D", +"A% c #202020", +"S% c #606060", +"D% c None", +"F% c #666666", +"G% c #6F6F6F", +"H% c #424242", +"J% c None", +"K% c None", +"L% c #5F5F5F", +"P% c None", +"I% c None", +"U% c #646464", +"Y% c None", +"T% c #515151", +"R% c None", +"E% c #6F6F6F", +"W% c None", +"Q% c None", +"!% c None", +"~% c #868686", +"^% c None", +"/% c None", +"(% c None", +")% c #585858", +"_% c #606060", +"`% c #5C5C5C", +"'% c None", +"]% c #5C5C5C", +"[% c #A8A8A8", +"{% c None", +"}% c None", +"|% c #4D4D4D", +" & c None", +".& c None", +"X& c #515151", +"o& c #5F5F5F", +"O& c None", +"+& c #CACACA", +"@& c None", +"#& c #636363", +"$& c None", +"%& c None", +"&& c None", +"*& c #ECECEC", +"=& c #545454", +"-& c None", +";& c #5F5F5F", +":& c None", +">& c #494949", +",& c #5C5C5C", +"<& c #4D4D4D", +"1& c None", +"2& c None", +"3& c None", +"4& c None", +"5& c #0D0D0D", +"6& c #4D4D4D", +"7& c #2F2F2F", +"8& c None", +"9& c None", +"0& c None", +"q& c #515151", +"w& c None", +"e& c #797979", +"r& c #515151", +"t& c #5F5F5F", +"y& c #585858", +"u& c #6A6A6A", +"i& c None", +"p& c #4D4D4D", +"a& c #737373", +"s& c #5B5B5B", +"d& c None", +"f& c #636363", +"g& c None", +"h& c #959595", +"j& c #6E6E6E", +"k& c #888888", +"l& c None", +"z& c #585858", +"x& c None", +"c& c None", +"v& c #B7B7B7", +"b& c None", +"n& c #5C5C5C", +"m& c None", +"M& c #676767", +"N& c None", +"B& c #545454", +"V& c #666666", +"C& c #575757", +"Z& c None", +"A& c None", +"S& c #636363", +"D& c #494949", +"F& c #D9D9D9", +"G& c #4D4D4D", +"H& c None", +"J& c #979797", +"K& c None", +"L& c #757575", +"P& c #FBFBFB", +"I& c #3E3E3E", +"U& c None", +"Y& c None", +"T& c None", +"R& c #575757", +"E& c #6A6A6A", +"W& c None", +"Q& c None", +"!& c #5C5C5C", +"~& c #545454", +"^& c None", +"/& c None", +"(& c #1C1C1C", +")& c None", +"_& c #5C5C5C", +"`& c None", +"'& c #7D7D7D", +"]& c #6B6B6B", +"[& c #5B5B5B", +"{& c #979797", +"}& c #3E3E3E", +"|& c None", +" * c #4D4D4D", +".* c None", +"X* c #6E6E6E", +"o* c None", +"O* c None", +"+* c #6A6A6A", +"@* c None", +"#* c #606060", +"$* c #585858", +"%* c #606060", +"&* c #757575", +"** c None", +"=* c None", +"-* c #5B5B5B", +";* c #828282", +":* c #4D4D4D", +">* c None", +",* c #585858", +"<* c None", +"1* c None", +"2* c None", +"3* c None", +"4* c #A4A4A4", +"5* c #535353", +"6* c #6B6B6B", +"7* c #C6C6C6", +"8* c #494949", +"9* c None", +"0* c #585858", +"q* c #4D4D4D", +"w* c #626262", +"e* c None", +"r* c None", +"t* c #636363", +"y* c #676767", +"u* c #E8E8E8", +"i* c #4D4D4D", +"p* c #6A6A6A", +"a* c #4C4C4C", +"s* c #575757", +"d* c None", +"f* c None", +"g* c #090909", +"h* c #888888", +"j* c None", +"k* c #666666", +"l* c None", +"z* c #4D4D4D", +"x* c None", +"c* c #575757", +"v* c None", +"b* c #2B2B2B", +"n* c #5B5B5B", +"m* c #494949", +"M* c #585858", +"N* c #4D4D4D", +"B* c None", +"V* c None", +"C* c None", +"Z* c None", +"A* c #6F6F6F", +"S* c None", +"D* c #626262", +"F* c None", +"G* c None", +"H* c None", +"J* c None", +"K* c #636363", +"L* c #767676", +"P* c #919191", +"I* c #757575", +"U* c None", +"Y* c #626262", +"T* c None", +"R* c #5B5B5B", +"E* c #585858", +"W* c #B3B3B3", +"Q* c None", +"!* c None", +"~* c #676767", +"^* c #6E6E6E", +"/* c #5C5C5C", +"(* c #D5D5D5", +")* c None", +"_* c None", +"`* c #727272", +"'* c #505050", +"]* c #494949", +"[* c None", +"{* c #5C5C5C", +"}* c #6A6A6A", +"|* c None", +" = c None", +".= c #5B5B5B", +"X= c None", +"o= c #F7F7F7", +"O= c None", +"+= c #727272", +"@= c #5C5C5C", +"#= c #181818", +"$= c #5F5F5F", +"%= c #494949", +"&= c None", +"*= c None", +"== c #3A3A3A", +"-= c None", +";= c None", +":= c #797979", +">= c None", +",= c #5C5C5C", +"<= c #5C5C5C", +"1= c None", +"2= c #585858", +"3= c None", +"4= c #A2A2A2", +"5= c #7E7E7E", +"6= c None", +"7= c #626262", +"8= c None", +"9= c #A0A0A0", +"0= c #505050", +"q= c #939393", +"w= c #6E6E6E", +"e= c #585858", +"r= c None", +"t= c #494949", +"y= c #C2C2C2", +"u= c #505050", +"i= c None", +"p= c #6A6A6A", +"a= c #575757", +"s= c #585858", +"d= c #E4E4E4", +"f= c None", +"g= c #494949", +"h= c #5E5E5E", +"j= c #626262", +"k= c None", +"l= c None", +"z= c #5B5B5B", +"x= c #050505", +"c= c None", +"v= c #585858", +"b= c #545454", +"n= c #636363", +"m= c #5E5E5E", +"M= c None", +"N= c #272727", +"B= c None", +"V= c #626262", +"C= c #6A6A6A", +"Z= c #676767", +"A= c #494949", +"S= c #363636", +"D= c #5E5E5E", +"F= c None", +"G= c None", +"H= c #6D6D6D", +"J= c None", +"K= c #6B6B6B", +"L= c #5B5B5B", +"P= c #4C4C4C", +"I= c #545454", +"U= c #8F8F8F", +"Y= c #8D8D8D", +"T= c None", +"R= c #575757", +"E= c #626262", +"W= c #585858", +"Q= c None", +"!= c #AFAFAF", +"~= c None", +"^= c None", +"/= c None", +"(= c None", +")= c None", +"_= c #D1D1D1", +"`= c None", +"'= c None", +"]= c #535353", +"[= c #545454", +"{= c #585858", +"}= c None", +"|= c None", +" - c #F3F3F3", +".- c None", +"X- c None", +"o- c #585858", +"O- c #141414", +"+- c None", +"@- c None", +"#- c None", +"$- c None", +"%- c None", +"&- c #363636", +"*- c None", +"=- c None", +"-- c #454545", +";- c #636363", +":- c None", +">- c #4C4C4C", +",- c #585858", +"<- c #5E5E5E", +"1- c #505050", +"2- c None", +"3- c #7A7A7A", +"4- c None", +"5- c None", +"6- c None", +"7- c #545454", +"8- c #9C9C9C", +"9- c #535353", +"0- c None", +"q- c None", +"w- c #BEBEBE", +"e- c None", +"r- c #6D6D6D", +"t- c None", +"y- c None", +"u- c #E0E0E0", +"i- c #454545", +"p- c #696969", +"a- c #5A5A5A", +"s- c #636363", +"d- c #545454", +"f- c #8F8F8F", +"g- c #535353", +"h- c #454545", +"j- c #575757", +"k- c #545454", +"l- c None", +"z- c #666666", +"x- c None", +"c- c None", +"v- c #5B5B5B", +"b- c #232323", +"n- c #727272", +"m- c None", +"M- c #454545", +"N- c #505050", +"B- c None", +"V- c #696969", +"C- c #626262", +"Z- c #5B5B5B", +"A- c #8B8B8B", +"S- c #545454", +"D- c #6E6E6E", +"F- c #676767", +"G- c #575757", +"H- c None", +"J- c #545454", +"K- c #575757", +"L- c #898989", +"P- c None", +"I- c None", +"U- c None", +"Y- c #4C4C4C", +"T- c #ABABAB", +"R- c #5A5A5A", +"E- c None", +"W- c None", +"Q- c #545454", +"!- c #5B5B5B", +"~- c #5E5E5E", +"^- c #787878", +"/- c #CDCDCD", +"(- c #808080", +")- c #545454", +"_- c None", +"`- c #EFEFEF", +"'- c #575757", +"]- c None", +"[- c #727272", +"{- c #7C7C7C", +"}- c #505050", +"|- c None", +" ; c #666666", +".; c #101010", +"X; c #545454", +"o; c #5E5E5E", +"O; c #5F5F5F", +"+; c #323232", +"@; c None", +"#; c None", +"$; c None", +"%; c #575757", +"&; c None", +"*; c #636363", +"=; c #535353", +"-; c #545454", +";; c None", +":; c None", +">; c None", +",; c #5E5E5E", +"<; c None", +"1; c #767676", +"2; c None", +"3; c None", +"4; c #575757", +"5; c None", +"6; c #989898", +"7; c #505050", +"8; c #696969", +"9; c None", +"0; c #636363", +"q; c #9A9A9A", +"w; c None", +"e; c #BABABA", +"r; c #626262", +"t; c #5B5B5B", +"y; c #5F5F5F", +"u; c #5E5E5E", +"i; c None", +"p; c #DCDCDC", +"a; c #6A6A6A", +"s; c None", +"d; c #717171", +"f; c None", +"g; c None", +"h; c #5E5E5E", +"j; c None", +"k; c #4C4C4C", +"l; c #FEFEFE", +"z; c None", +"x; c None", +"c; c #757575", +"v; c None", +"b; c #575757", +"n; c None", +"m; c #717171", +"M; c #1F1F1F", +"N; c #5B5B5B", +"B; c None", +"V; c #414141", +"C; c #5E5E5E", +"Z; c None", +"A; c #414141", +"S; c #3D3D3D", +"D; c None", +"F; c None", +"G; c #656565", +"H; c #696969", +"J; c None", +"K; c None", +"L; c #636363", +"P; c None", +"I; c #505050", +"U; c None", +"Y; c None", +"T; c #575757", +"R; c #8B8B8B", +"E; c #6E6E6E", +"W; c None", +"Q; c #858585", +"!; c None", +"~; c None", +"^; c #575757", +"/; c None", +"(; c #5A5A5A", +"); c #A7A7A7", +"_; c #6E6E6E", +"`; c #505050", +"'; c #C9C9C9", +"]; c None", +"[; c #747474", +"{; c #575757", +"}; c None", +"|; c #5E5E5E", +" : c None", +".: c #EBEBEB", +"X: c #5B5B5B", +"o: c #4C4C4C", +"O: c #5A5A5A", +"+: c None", +"@: c #0C0C0C", +"#: c #747474", +"$: c None", +"%: c None", +"&: c #2E2E2E", +"*: c #575757", +"=: c #5E5E5E", +"-: c #505050", +";: c None", +":: c None", +">: c #505050", +",: c None", +"<: c None", +"1: c #656565", +"2: c #484848", +"3: c #4C4C4C", +"4: c None", +"5: c None", +"6: c #5E5E5E", +"7: c #5B5B5B", +"8: c #6E6E6E", +"9: c #6A6A6A", +"0: c #727272", +"q: c None", +"w: c None", +"e: c #3D3D3D", +"r: c #949494", +"t: c None", +"y: c #5A5A5A", +"u: c None", +"i: c #666666", +"p: c #B6B6B6", +"a: c None", +"s: c #4C4C4C", +"d: c None", +"f: c None", +"g: c None", +"h: c #3D3D3D", +"j: c #D8D8D8", +"k: c #5F5F5F", +"l: c #4C4C4C", +"z: c None", +"x: c #787878", +"c: c #5A5A5A", +"v: c #FAFAFA", +"b: c None", +"n: c None", +"m: c #656565", +"M: c None", +"N: c #5F5F5F", +"B: c None", +"V: c #3D3D3D", +"C: c #1B1B1B", +"Z: c None", +"A: c #3D3D3D", +"S: c #4C4C4C", +"D: c None", +"F: c None", +"G: c None", +"H: c None", +"J: c #5F5F5F", +"K: c #484848", +"L: c #969696", +"P: c None", +"I: c #5E5E5E", +"U: c #616161", +"Y: c #5F5F5F", +"T: c #616161", +"R: c #6D6D6D", +"E: c None", +"W: c #5B5B5B", +"Q: c None", +"!: c None", +"~: c #818181", +"^: c None", +"/: c #4C4C4C", +"(: c None", +"): c #5E5E5E", +"_: c #A3A3A3", +"`: c None", +"': c None", +"]: c #666666", +"[: c #6A6A6A", +"{: c #C5C5C5", +"}: c #5A5A5A", +"|: c #4C4C4C", +" > c None", +".> c #575757", +"X> c None", +"o> c #747474", +"O> c None", +"+> c #535353", +"@> c #E7E7E7", +"#> c #747474", +"$> c None", +"%> c #4C4C4C", +"&> c None", +"*> c #656565", +"=> c None", +"-> c #6A6A6A", +";> c None", +":> c #616161", +">> c #4C4C4C", +",> c #080808", +"<> c #656565", +"1> c None", +"2> c None", +"3> c #5B5B5B", +"4> c #707070", +"5> c None", +"6> c #4C4C4C", +"7> c #2A2A2A", +"8> c None", +"9> c None", +"0> c None", +"q> c #4C4C4C", +"w> c #535353", +"e> c #616161", +"r> c None", +"t> c #6E6E6E", +"y> c None", +"u> c #4F4F4F", +"i> c #5B5B5B", +"p> c None", +"a> c None", +"s> c #909090", +"d> c None", +"f> c None", +"g> c None", +"h> c #4B4B4B", +"j> c None", +"k> c None", +"l> c #5A5A5A", +"z> c None", +"x> c #B2B2B2", +"c> c #656565", +"v> c #707070", +"b> c #7F7F7F", +"n> c #535353", +"m> c None", +"M> c #616161", +"N> c #747474", +"B> c None", +"V> c None", +"C> c #D4D4D4", +"Z> c None", +"A> c None", +"S> c #5E5E5E", +"D> c #575757", +"F> c #5A5A5A", +"G> c None", +"H> c #A1A1A1", +"J> c None", +"K> c None", +"L> c #F6F6F6", +"P> c #616161", +"I> c #393939", +"U> c None", +"Y> c None", +"T> c #171717", +"R> c #535353", +"E> c #393939", +"W> c #757575", +"Q> c None", +"!> c #616161", +"~> c #787878", +"^> c #393939", +"/> c #575757", +"(> c #4F4F4F", +")> c #5A5A5A", +"_> c None", +"`> c None", +"'> c None", +"]> c #5B5B5B", +"[> c #616161", +"{> c #707070", +"}> c None", +"|> c #575757", +" , c None", +"., c None", +"X, c None", +"o, c #535353", +"O, c None", +"+, c #7D7D7D", +"@, c #484848", +"#, c #5E5E5E", +"$, c #787878", +"%, c #9F9F9F", +"&, c None", +"*, c #5A5A5A", +"=, c #707070", +"-, c None", +";, c #696969", +":, c None", +">, c #696969", +",, c #C1C1C1", +"<, c None", +"1, c #4F4F4F", +"2, c None", +"3, c #5D5D5D", +"4, c None", +"5, c #5E5E5E", +"6, c None", +"7, c #484848", +"8, c #6D6D6D", +"9, c #535353", +"0, c #E3E3E3", +"q, c None", +"w, c None", +"e, c #575757", +"r, c #616161", +"t, c #484848", +"y, c None", +"u, c #5A5A5A", +"i, c #444444", +"p, c #929292", +"a, c #484848", +"s, c #262626", +"d, c None", +"f, c None", +"g, c #575757", +"h, c #616161", +"j, c None", +"k, c None", +"l, c #535353", +"z, c #484848", +"x, c None", +"c, c None", +"v, c None", +"b, c #575757", +"n, c #666666", +"m, c None", +"M, c None", +"N, c #6A6A6A", +"B, c None", +"V, c #535353", +"C, c None", +"Z, c None", +"A, c #666666", +"S, c #8C8C8C", +"D, c None", +"F, c None", +"G, c #626262", +"H, c #AEAEAE", +"J, c #6C6C6C", +"K, c #5A5A5A", +"L, c None", +"P, c #535353", +"I, c #656565", +"U, c None", +"Y, c #565656", +"T, c #D0D0D0", +"R, c #5A5A5A", +"E, c None", +"W, c #535353", +"Q, c None", +"!, c #575757", +"~, c #5D5D5D", +"^, c None", +"/, c #707070", +"(, c #4F4F4F", +"), c #F2F2F2", +"_, c None", +"`, c None", +"', c #717171", +"], c None", +"[, c #131313", +"{, c None", +"}, c #353535", +"|, c #5E5E5E", +" < c None", +".< c #535353", +"X< c None", +"o< c None", +"O< c #575757", +"+< c #9D9D9D", +"@< c #747474", +"#< c #575757", +"$< c #4F4F4F", +"%< c #6C6C6C", +"&< c None", +"*< c #656565", +"=< c #797979", +"-< c None", +";< c None", +":< c None", +">< c None", +",< c #5A5A5A", +"<< c #5D5D5D", +"1< c #535353", +"2< c None", +"3< c #9B9B9B", +"4< c None", +"5< c None", +"6< c None", +"7< c #656565", +"8< c None", +"9< c #BDBDBD", +"0< c #616161", +"q< c None", +"w< c #444444", +"e< c #DFDFDF", +"r< c #5A5A5A", +"t< c #595959", +"y< c #696969", +"u< c None", +"i< c #444444", +"p< c #535353", +"a< c #787878", +"s< c #000000", +"d< c None", +"f< c None", +"g< c #717171", +"h< c #4F4F4F", +"j< c #4B4B4B", +"k< c None", +"l< c #222222", +"z< c #5D5D5D", +"x< c None", +"c< c #616161", +/* pixels */ +" ", +" ", +" ", +" P%8#8#8#8#6,I%Q:fc yo*=.%5 **X,7%%:LXn$C%;#G$8#8#8#8#P% ", +" P%8#v%v%8#VoKOM,fO;$'>A&e 2%LOLOG%3X8.6*[:e$CXZ=Z=->Ho4@,@E;G%G%g<8:@3*%-gO8#v%v%8#P% ", +" P%v%8#O>%XF m-J=;>> ZX.o9:X%(Xl,h<($F.>:>:s@N*q>N*a#z,a#a#a#a#WXq>N*s@s@F.F.r&&.l,l,z#(XX%2%L* =x,PXJ=AXJ>6-s#v%8# ", +" P%v%v R$g u:9@i;]oD-n=o,4XY-/:N*a#z,M-H%A;*.!+!+}&,XQ@==,X==^>^>^>qo^>==Q@Q@,X}&!+!+*.A;A;`O. z,WXN*F.N-oX$*|+SXh$P #Ou:K#%&h v%v%P% ", +" $ 8#v d@W;wX5Xd#+=Q#~&:.F.s@a#. A;A;!+,X^>&-_#},-%j +;y+y+7&7&7&7&7&7&7&j y+7&7&y+7&7&y+y+j +;+;tO&-_#qo==,X}&A;H%. z,s@r&7,fop i:EO&&m$J;K;-=P%8#P% ", +" $ v%=**-U,^.p,8,p$Xo##F.A=. H%}&qo_#&-tO+;y+j y++;-%y+y+j -%+;+;-%tOtOtO},tOtO},tOtOtOtOtO+;+;j +;j j +;j j j j j +;-%tO&-^>Q@A:*.M$z,F.r&>-4;1#-OWO^&,:&Xuo$ P% ", +" P%n.(:a>J%G.K-E$z*>:A=`O*.Q@_#&--%j j j j +;j j -%},_#qoqo==A:}&A;*.H%H%. . `O. . `O. . . . `OA;A;A;*.A:A:Q@qo_#&--%+;+;-%j -%+;j j tO_#Q@,X*.M-_oF.f+k;=;S&D@c&_ K>c, ", +" {#Q%g&a%>,Y,a.-;A=M-*.==_#},+;+;j +;+;j -%tOqoQ@,XA:A;`O. M-z,A=A=WXN*N*>:>:r&>:>:r&r&r&r&r&r&f+>:F.F.s@N*a#z,_oM$. `OH%A;*.,X==_#tOj y+j j +;+;-%_#^>,X*.z,a#s@7-L#):_+^.Q=eXI ", +" T+IXl=|=>.g-*X3%z,M-A:==_#-%j +;y+y+-%},^>A:!+H%. M$z,A=q>s@r&-;-;3%,-}#]><=<=6XY:Y:%*%*`+`+`+,.`+%*%*Y:Y:6X<=]@]>,-hO3%b f+F.N*WXA=_o. `OA;A:==_#+;j y+y++;+;tO^>A:*.M-A=s@e,j$-*-o|&W${$s# ", +" r$x#y-&*,;l%+>WX`O,X^>},-%+;j 7&+;_#==A:*.H%M-z,q>F.>:f+hO,-io<=`+L;}O% Z$N,K=K=)XA*t>t>A*A*h@h@A*A*A*t>A*h@A*)Xc#c#N,F-Z$% }OL;]@io}##:s@a#M$`O!+}&,X_#tOy+7&+;-%tOqo,X!+. WX>:,-s%<-o%/&K%5; ", +" P%K.n%^-].m=/>F.M-*.^>},-%j 7&y+tOqo,X!+A;M-A=N*F.f+3%,-<=%*,.% Z$N,K=A*L.L.h@A*A*t>A*t>)Xt>A*A*A*t>)XN,c#)Xt>A*A*A*t>A*A*A*t>A*h@A*A*c#K=K=F-U%L;Y:<=,-b >:N*WXM$`OA;}&Q@&-+;7&7&+;},qo,XA;M$q>b .=[.- X={$y> ", +" G$` 6+!@[>@=F.A=A;==&--%y+7&j },^>,X!+`Oz,WXs@b 3%]>Y:L;F-N,c#A*L.h@h@A*A*t>)X}O6X]>]>io]>]>]>`+,.}OZ$N,c#t>A*c#N,Z$}O`+Y:<=ioioioio]>6X}Ot>h@A*A*A*A*c#[oZ$}O`+6Xio-;F.N*A=M-A;A:==&--%7&y++;&-^>!+. a#F.,-~@t<8&:$x*8# ", +" !%n }$9./.5@t=M$!+^>tOy+7&j tO_#,X}&. z,q>>:3%ioY:U%F-K=t>L.h@h@0:)XU%6X<=io<=U%K=A*h@h@A*t>h@a&c++$5= @H$s>M+y%mOh&n#X+rXgokOc+h@A*A*h@L.L.t>Z$`+}#io6XY:F-)Xh@h@t>K=[o}O`+<=hOb N*a#M-A;}&^>&-+;7&j tO_#==*._oh-r&1#jX~+O,cXG$ ", +" !%s#t@B-j&F@8%. ==_#+;7&7&-%qoQ@!+`Oz,N*r&hO]>,.% K=A*A*A*L.A*F-6X<=L;N,c#)XK=Z$A*+,P*iXoov&U e;d%e;e;d%BOCoy=:#kXkX{:{:y=5$9<9Y ", +" 8#R$wo7X[X9,xo`OQ@},y+&:y+tOqo!+. _oq>>:hO]@,.F-)XA*h@L.A*% ]@Y:}O[oF-% a&S,$#!=b@W*b@e;y=<@/-_=G##oC>G#_=T,_=_=_=;O;O)$)$;OT,T,_=G#G#_=G##o_=T,;O/-<@w-V+b@b@A#, >$~%t>U%[oZ$L;6X`+N,h@L.)X[o}OY:}#f+F.a#. !+==&--%j y+-%qo,X. a#UX]%9#POQXX v ", +" P%u%#O{oa$(,a,`O==+;y+7&-%tO^>*.M-a#F.hO]@`+Z$A*L.0:0:Z$%*,.Z$Z$U%L;c+E.$+!=b@Co+&)$#o(*#oG#T,)$>+>++&>+)$/->+/-6 6 /-/-6 /-6 /-/-)$/-/-)$/-6 +&6 +&+&6 6 T,#o(*G#_=/-7*BOooQ$@@ Ot>,.% N,F-,.L;c#L.t>N,L;%*iof+WX_o`OA:_#tOy+7&j &-,X. a#k;DX{>X.QXcX ", +" cXY>[@COo+IOH%Q@+;j y++;&-A:`O_oq>b ,-6X% )Xh@a&a&K=L;F-}O6X,.kOM+);$+A#y=_=V@#oT,)$>++&6 /-;O)$;O)$)$)$)$T,G#_=G#T,;OT,_=T,G#_=G#_=#o_=T,G#_=T,;O;O)$)$)$/-)$/-6 +&>++&>+T,C>#o6 93%F.A=M-*.^>tO+;y+j &-,X. q>$a#`O^>+;y+y+-%qoQ@`Oa#r&-;ioL;N,A*0:0:)X% % U%]>Z$H$9=@@A#kXG#C>_=;O+&>+/-/-/-;O;O;OT,G##oG#G##o#o#o#o(*C>(*V@(*(*V@V@V@V@V@(*V@V@C>(*(*C>#o#oG#_=_=G#T,;O;O;O/-/-/-6 +&>++&)$C>G#6 w-Q$_:3<.#%*]@Z$[oZ$)Xh@c#U%6X#M$*.Q@},j y+y+_#A:M-s@D&i#T Oo;% ", +" `#_$ <.@(>h:==tOy+y+j ^>}&. A=r&,-]@,.c#h@c+t>[oZ$U%io`+0.6;iXd%;O#o;O6 +&>+6 /-)$;OG##oT,G##oG##o#o(*(*(*j:j:j:j:j:j:j:F&D+D+W W W W F&j:j:{.j:j:j:F&j:{.(*(*(*C>#o_=#oG#T,G#_=T,)$;O/-6 +&';+&>+;O_=';x>coE.go]@<=}OZ$[o)XA*F-6X}#b q>_oH%Q@},j y+-%==!+. f+G&G x,k -= ", +" .Oo.<;r;u=z,!+&-j y+j _#A:`OA=>:3%6X% c#A*L.K=K=L;#+6 /-)$T,_=T,G#G#C>V@V@V@j:V@{.F&D+D+D+D+p;p;z%z%p;z%z%p;z%ZOZOZOZOz%z%z%z%z%z%z%p;W D+D+D+D+F&j:{.j:{.(*(*C>G#G#G#_=T,)$/-6 6 >+';';>+)$7*H,M+n#a&,-io[o)XN,c#K=`+iob WXM-*.,XtOy+j tO==A;_o}-vo!XO.y@ ", +" _XXOS*m.r&`Oqo+;y+y+&-A:A;A=F.3%<=U%c#L.L.N,F-]>]@1;L-h&oo>+6 >++&6 /-)$;O;OT,G#G##oC>C>{.{.F&D+F&D+W p;z%z%ZOZOZOZOe#o_=T,T,T,/-)$6 +&';s.+&6 y=@@n#Q;t>#M-!+qo-%y+y+tOQ@`Os@q.s&]Ol=k@ ", +" k$3&#@c:OXM-,XtOy+y+},==A;_oN*3%<=% t>0:h@N,Z$,-%*=< O$+7*6 +&+&6 6 )$)$;OT,T,G#(*C>(*{.j:F&F&W p;p;ZOZOeG#_=T,)$)$/-6 6 >+';';s.9<>$ @0:]>]>N,K=)Xc#L;,->:WXM-}&_#j y+j _#*._o/:,;0N*R+_#+;y+-%==!+M$q>b <=U%c#L.h@c#U%,-% +$H$x><@6 /-/-/-/-;OT,T,_=#o#o(*j:F&F&W W W ZOZOe2#vX@>2#@>u*u*l.6@l.6@l.u*u*u*@>@>vXvXvX@>vX2#0,d=d=0,KoKot$u-u-e+>+>++&s.,,u.Q;c+`+}#}OK=c#[o,.#<>:z,A;,X&-j y+},Q@`O/:bXQOr,d&I ", +" P%];l@c*tXA;==+;7&+;_#}&M-WXf+ioL;K=h@L.)XY:]>K==< OU kX>+)$;O6 )$;OT,_=#oC>(*j:F&F&D+W ZOZOe@>@>d=d=0,t$Kot$u-u-u-z%p;D+D+D+{.{.C>G##o;OT,;O>+>+>+/->+s.kX$OX+c+U%,-L;t>K=[oY:3%s@z,A;Q@-%7&+;qo*.. S:3>t&B:Y@cX ", +" $ 2o4%w+|+3oe:},y+7&-%Q@H%A=>:,-`+K=c+A*t>`+%*K=9%h&w-:#6 T,/-/-/-T,G#G#(*{.j:j:D+W z%ZOZOZOu-t$0,0,0,d=2#@>u*6@l..:6@6@*&7+7+7+r `-`-4O|$|$|$|$|$|$|$|$|$|$|$`-`-|$|$|$r r r r 7+*&.:.:*&.:6@u*vX2#2#2#0,KoKoKoe+>+6 6 <@kXb@S,0:F-]>`+h@c#F-6X#u*6@.:7+r 7+r |$r r 4O),4O4O),),;o;oL>P#P#;oP#P#P#P#P#;oL>L>;o;oP#4O4O), -4O`-r |$|$r r 7+l..:6@u*vX0,0,2#KoKoe#oT,)$;O/->++&)$>+<@e;P*K=U%Y:[ot>c#U%]>f+a#H%==-%7&-%&-!+_o!#)>6$Lo P% ", +" +%5O:>Z%}&&-y+7&tOA:`OA=b ]>U%c#a&a&F-`+U%N,M+d%7*;O;O>+/-;OT,G##o(*C>j:p;p;p;eL>o=L>o=G@v:I+v:+X+X+X+X+X+X+Xv:P&P&v:+Xo=L>L>G@L>P#P#P#P# -), -),`-`-7+.:.:l.u*vXu*2#2#0,0,t$eG#T,T,;O)$+&+&/-+&{:b@ OF-L;%*K=t>Z$%*hON*M-!+qo-%j },,X`O *X:y<`=F+ ", +" ,$=-4>g+:.A:-%&:y+qo!+_os@hO6XN,0:c+c#`+% 6XH$A#kX/-/-6 )$;O;OG#C>V@V@F&W z%p;e@>6@6@.:*&r |$),),), - - -L>o=L>o=v:+Xv:P&P&P&P&P&I+' ' m%m%m%m%m%m%m%m%l;I+I+' P&P&I+v:v:+Xv:G@o=G@G@P#;oP#),),4O`-r 7+7+l.6@u*u*@>2#d=u-t$t$ZOp;W D+j:V@C>C>_=T,;O/-+&';>++&,,$O9%U%L;L;)Xt>U%}#r&A=A;Q@&-7&+;qo*.q>l L=z;4o ", +" D:5>V-UX_o,X+;7&-%==H%WXb ioL;)XV A*U%U%Y:=<4*w-+&>+6 /-)$;O_=#oV@(*{.D+z%e@>u*l..:r r |$4O -P#P#L>L>L>+Xo=I+I+I+P&l;m%m%m%m%' I+' I+' I+P&I+I+I+I+v:P&I+I+I+I+' ' ' m%m%m%m%m%I+P&I+I++X+Xo=L>;o - -),4O4O7+`-.:*&.:u*@>2#KoKot$ej y+},,X. N*3%]@Z$c+0:% ,.<=Z$8-V+s.>++&6 ;OT,G#C>V@F&F&F&z%p;u-t$0,d=d=vXl.l.l.7+r |$4O4O -P#;oo=G@G@+XI+l;l;m%l;' I+I+' ' I+P&P&v:v:P&v:G@;oL>G@o=o=L>o=L>o=+Xv:+X+Xv:v:I+' ' ' l;' I+l;m%l;P&I+v:L>o=L>;o -),4O4O|$r 7+l.6@u*vX2#0,u-u-e+';';+&,,x> O% Y:}O[oh@`+,->:z,A;qo+;7&tO}&. 3#z=!:oOI ", +" <,8XP>Z%!+_#7&j qo!+_or&io,.K=c+t>% ]>]@; , kX+&>+6 )$;O_=C>(*(*{.p;p;eo=L>;oo=o=G@+Xv:+Xv:' ' I+I+m%l;l;I+v:v:o=o=;o -),4O`-`-.:.:l.@>vX2#d=t$e+';7*s.U [%3-io`+F-)X[o<=-;WXA;^>tOy++;==. &.8+x.v, ", +" P-m Po2:Q@-%y+j ^>A;a#b ]@F-L.a&K=Y:]>L.y%9<6 6 >+/-;OT,_=C>V@D+W z%z%e6@*&7+r 4O - -P#o=G@+XP&' l;l;I+I+I+P&P&P&G@+Xo=G@o=P#4O*&2#z%W j:V@C>_=)$';kXw-U v&v&d%,,<@+&)$#o(*j:F&p;t$@>*& -L>G@P&+Xv:v:+XI+l;' ' m%l;I+v:G@G@o=;oP#|$r 7+7+.:6@vX2#0,Kou-e+';';';b@s>c#<=[o[ot>%*hOq>`OA:&-7&y+qo`ON*i*m#Q v ", +" Y%#>j-f.^>+;y+tOQ@`OWX-;%*K=a&h@N,6X`+;*$+s./->+/-)$T,G#C>(*{.D+z%e;oG@P&l;m%' l;m%' P&+Xo=o=G@L>4Ol.Kot$p;#o7*v&[%mOY=rXV c#[oU%%*<=#<3%b b -;}#]@%*% c#a&+$ @n#co!=BO>+V@p;u-vX7+),o=G@v:I+I+m%l;' m%I+I+P&+Xo=;o),4O|$`-*&l.6@@>2#0,Kot$e#o_=;O/-+&+&s.>+,,$#=<}#F-Z$)X% ioF._o}&&-y+j qo!+A=bXm#$@Z>v ", +" G$nX%<0%i-I>j y+&-!+M$s@,-,.t>c+)XU%]@N,E.e;>+/-/-)$T,_=G#V@{.j:D+ZOt$u-0,d=@>u*.:l.r |$4O),;oL>G@v:I+' ' ' ' P&v:v:+XG@;o|$u*t$V@s.b@4*z@5=h@,.io3%>:z,*.,X},-%tO-%-%tO},},},-%+;j j +;},_#Q@!+M-N*b ]>}OV X+H T-d%;Op;d=*&),o=v:+Xl;' l;l;l;' P&+XG@;o -4O|$r *&l.@>vXvXd=Kou-eG#_=;O/->+';<@s.A#.#F-%*Z$A*[o]@f+_o*.qo+;j },}&z,3#R,`$k@_, ", +" c,e-N+k-M$qo7&7&qo!+A=f+io}Oh@0:)XY:,.0:cos./-6 )$;OT,G#(*{.W p;z%e%*ioWX}&},tO_#,XH%_oa#s@r&f+-;3%,-]>6X6X<=]>,--;>:N*WXz,. A;Q@&-j &:7&&-A;WX#<%*0:H$@@d%6 W d=7+;oo=v:I+' l;l;I+' P&G@;o;o -|$r *&l.l.@>d=d=Kou-ZOp;W F&{.C>G#)$;O6 s.';';5$H$V 6X[oc#[oY:f+N*H%Q@-%7&tO}&M$g=8OU>{@H# ", +" u<%OD*:*. qoy+j ^>H%a#b <=Z$L.0:[oY:Z$~:!=/-+&6 ;OT,T,C>V@j:D+z%ZOu-0,vXu*6@6@*&r 4O4O;oL>o=v:' l;' m%P&v:P&G@P#`-u*W +&p:%,~%a&L;f+H%},qoH%a#r&#<]@% Z$c#A*0:a&a&c+a&a&a&a&a&a&0:0:h@A*)Xc#N,[oF-}O`+]>,--;WXM-}&qo+;u@y+}&b }O9%{Xu.w-G#t$*&P#o=+XP&I+' I+' P&G@;oL> -),`-7+6@@>vXvX0,Koe_=T,;O6 +&7*<@{:iXgoL;L;N,K=,.#`ON*3%6XN,V A*U%%*)Xr:y=/-s.6 ;OT,#o{.F&W z%z%ZOt$d=2#@>l.7+r |$),;oL>o=v:I+' ' l;v:G@L>;o4O6@ZO/-p:mO.#N,-;,X-%,XM$r&<=Z$t>c+kO+$rX;*;*;*rX;*rX+,+,5=5=+$=<=<9%9%1;1;1;V c+c+a&a&L.0:h@)Xc#[o}OY:iohOF.M-==j b*j A;#<)X~%iXBOV@d=`-;oo=v:' l;I+l;P&+Xo=L>;o -|$*&l.u*vXd=0,u-z%z%p;F&{.(*#oT,;O+&';7*<@d%5=Z$,.Z$h@L;ios@M$A:tO7&tO,X. h-!$+ob&H# ", +" |-!;0#/:*.&-j -%==`Os@#<,.)Xc+t>,.U%h@4*)$+&>+)$T,T,G#(*j:D+p;ZOt$t$0,vX6@.:r 4O), -;oo=+XP&' m%l;v:o=;o4O*&2#C>w-_:Q;K=>:^>qoM$b 6X[o0:+$rX0.~%X+~%; ~%0.0.0.;*;*~:~:.#.#5=+$go3-=t>)Xc#N,N,% `+}#3%s@H%^>y+7&!+,-c+P*$O<@W u*),L>v:' m%m%I+v:G@;oP#),4Or 7+l.@>2#0,Kou-z%D+F&{.C>_=T,;O6 +&<@{:7*Y=K=,.}OL.U%]>f+_oA:_#y++;,X. i7&tOQ@`ON*,-L;t>c+c#6X}OkO!=)$s.6 )$;OT,G#V@D+z%p;ZOt$0,2#vXu**&r 4OP#P#o=v:' m%m%' v:G@;o4O.:ZO';!=r:V >:^>Q@WX}#F-a&go @L- O OH$L-L-; X+L-X+Q;Q;0.0.;*~:~:rX5=.#.#5=gogogo+$=<3-=<1;V c+a&a&0:L.L.L.A*t>t>K=c#N,Z$F-% }O]@<=L;t>V U%a#. 6X~:>$e;#o2#`-;o+XI+l;m%l;v:+Xo= -|$`-7+*&u*d=0,Kou-z%W W F&(*_=)$/-6 +&s.7*7*>$h@`+% 0:% ]>r&M$}&&-7&+;,X. 6>K-9*;;Y ", +" P%&hOL;)X0:N,%*U%+$W*/-+&>+/-_=C>(*{.D+z%eG@v:' ' m%' ' v:L>4Ol.p;:#u.X+6XA:}&A=hO% V +,Q;H$S,Y=Y=n#Y=Y= O OH$L-; X+; ~%Q;Q; @;*;*;*rX5=5=.#gogo+$3-=<={XU w-e;!=8-~%A*6Xz,M$Z$P*b@;O2#4OL>v:' m%l;I+P&G@;oP#),`-*&l.6@2#0,t$t$e#oT,6 +&';<@kX_:c+Y:,.h@[o<=r&_o,X},7&+;A:. q>=&AO,+Y ", +" %@8;9OA;&-7&+;Q@`Os@,-L;A*a&K=Y:% @(.6 >+/-;OT,#oV@j:F&p;ZOel.*&*&`-),P#G@P&' m%' P&P&G@P#.:D+y=iX+$f+A:_of+Y:0:~:; n#s>s>s>s>P*s>n#Y=n#S,S,L- OL-; ~%Q;Q;Q; @ @;*~:~:rXrX5=.#+$+$go=<=<= -4O7+.:l.u*2#0,t$e+)$6 ;O_=G#C>F&W p;t$0,d=@>6@l.7+|$4O;oL>G@I+' l;' v:G@P#r W 5$co0:N*A;z,3%)X.#H$s>r:M+h&h&E.P*P*P*s>{X{Xn#S, O; L-L-X+~%Q;~%0.0.~:;*;*.#.#.#5=5=+$+$3-+$kOkOkOV V c+V a&L.L.L.A*c#N,Z$h@mOx>BO6 C>_=;O/-_=;O)$/-6 {:e;u.L-)X#2#0,t$ZOW D+(*C>_=;O/-/-s.7*:#!=~:<=% K=[o6Xb z,}&&-y+-%Q@. s@v+-&N$ ", +" v%P;FX $_o&-y++;Q@H%s@#+/-;O_=C>V@F&p;u-t$0,d=u*l..:r ),P#;oo=P&I+m%P&+XL>;o*&p;,,y%K=a#M-A=,-L.~%P*H 6;H M+H M+M+r:E.E.P*{Xn#{X{XY= OL-L-X+; ; Q;Q; @0.~:rX~:rX.#5=5=+$3-+$3-3-=<=#o;O>+)$)$/-;O_=T,_=T,T,T,6 ,,H,P*A*#d=u-eT+ ", +" 8#h+@; %YX_#y+j ==`Oq>}#L;A*L.Z$%*t>>$y=)$6 /-)$G#V@j:F&p;ZOKo0,2#u**&`-|$),;oG@+XI+l;' P&G@;o7+Ko<@_:A*N*H%z,Y:=< Or:3<3+)$)$>+6 G#_=_=_=_=#oC>#o/-{:(.y%a&hO>:3%goW*(*l. -v:l;' ' v:o=L>;o),`-*&.:@>0,t$u-ZOp;j:{.#oT,;O6 ';<@';d%L-%*,.F-F-Y:-;z,}&&-7&-%A:z,F.f%:O-= ", +" j+F:q#j<7 7&+;Q@. N*#+)$)$G#j:F&D+z%ZOu-d=2#u**&r ),P#;oo=v:l;m%' +XL>4OvX)$$OrX-;A;_o`+5=P*mO>$co8-3<3{XS, OH$~%X+Q;0. @;*~:.#~:.#.#5=+,3-go3-=<=<=<9%9%1;V c+0:0:0:)X[o0:~%z@);<@T,';,,Co:#kX{:{:<@s.';>+/-T,_=_=_=G#C>C>G#(*(*#o>+e;%,1;r&N*,. Od%D+r L>I+m%m%P&+XG@;o),|$r l.u*2#d=u-z%p;F&j:(*T,)$6 +&7*s.,,H$L;`+N,N,Y:r&_o}&tOy+tOA:A=b ~&! z> ", +" {$}%P>|%==j j ^>. s@,-U%h@a&F-6XL._:;O>+6 )$_=G#V@F&D+z%u-t$d=u*l.7+`-4O;oo=+XP&I+m%P&o=P#l.j:V+{X6XA=!+]>.#z@8-$#$#%,co8->$8-3<3n# O; 0.~:~:.#+,go+$+$=t>N,F-N,9%~:S,Q$y=9#o(*#oV@(*(*6 d%8-A*q>N*t>3<{:u-|$+Xl;l;I+v:G@;oP#`-.:*&u*2#0,t$e}#}@r+` ", +" c,8 V.3:Q@-%y+qoH%q>,-L;)X0:N,Y:c#iX)$>++&)$_=C>{.F&W ZOt$0,2#6@6@*&`-),;o+XI+m%m%' v:o=4OKo7*>$c#>:Q@3%1;{X8-iX$#9=9=9=co8->$8->$mO6;6;6;H M+r:P*n# OQ;rX3-9%c+L.L.h@A*A*)X)X)Xc#c#N,[oN,[oF-Z$F-% % % % `+Y:F-)Xc+z@, );iX%,%,9=9=$#iXiXiX4*@@);Q$x>U 5$7*+&T,_=#o_=C>C>C>(*(*{.C>(*C>C>>+ooY=6Xz,#<=<, C>7+L>I+m%m%' P&L>),|$r 6@@>u*2#t$ZOp;F&V@{.G#)$/->+{:';kXL-,.,.)X[o<=f+_o,X-%j &-*.lXn*I.$>l- ", +" d&UOG+}&+;j &-!+WXhO,.)Xa&N,Y:N,%,';6 >+)$_=(*V@{.D+ZOKo0,2#@>l.*&`- -L>+XP&' ' I++X -*&W (.;*hOA:q>c#X+y%9=_:_:iXiX9=9=9=co>$>$8-mOmOy%6;H h&h&P* O @goc+)X[oU%L;L;%*6XY:Y:6X<=<=<=<=]>ioio}#io,-#L-0.Q;~%~%~%~%~%X+; X+; H$S,P*6;9=Q$p:5$7*/-T,_=_=#o(*C>(*C>V@C>V@#o#o(*G#,,@@;*b . `+s>,,0,),P&l;l;P&+Xo=L>4O7+l.u*vXd=t$e_=;O>++&{:s.:#~%Y:U%)XF-<=>:M-Q@+;y+qoH%N*R*@$~$G$ ", +" X#[;I;H%},y+tO}&A=-;`+c#a&c#Y:Z$h&,,)$>+/-T,C>{.j:F&p;t$d=vXu*l.7+|$ -L>+XP&l;m%P&L>P#6@G#@@)X_o*.U%~:E.$#u.@@4*4*iXiXiXiX9=9=%,>$>$mO3N*q>q>q>WXa#a#a#A=A=a#z,M$_o_oM-F.}O)XK=F-Z$Z$Z$[oZ$N,[o[oN,N,N,K=K=c#0:kO~:S,3<, U kX+&)$T,#oG##o(*(*#o(*V@V@(*V@{.j:C>/-e;3A=N*kOb@e<4OG@' l;I+v:;o;o),`-l.6@vX0,0,e+7*s.9<0.]>U%)XZ$ioN*`Oqoy+y+==M$N*s%c u+ ", +" 8#,$/=n&A===y+-%Q@M$b ]@[oc+c#Y:% Od%/-6 )$_=(*V@F&F&p;t$d=d=u*.:r 4OP#;oG@' m%' P&+X),2#';M+io!+b V n#$#4*u.););@@@@4*$#iXiX9=9=co8->$3<3<3^>==qo^>^>_#_#qo&-},qoH%N*N*q>N*N*q>N*q>N*q>q>s@s@N*F.s@N*s@>:r&#<6XZ$+$Y=9=W*Co<@6 _=#oG#C>V@(*(*(*V@{.V@V@{.j:{.(*G#<@!=S,io*.Z$4*C>7+G@I+l;' v:o=P#4O|$7+6@vX0,0,e+7*<@(..#}#L;A*}O,-q>A;&-&:+;A:M$r&mXd>H# ", +" P%R$i.h=w.==y++;==M-r&]@[oa&t>%*L;rXv&6 6 )$;OG#V@j:D+z%u-0,vXu*l.`-4O),L>P&l;m%' o=;o`-z%p:Q;a#A:6X;*3<);$+$+, ););u.@@@@_:_:iX_:9=9=co>$8-mOmOy%h&r:s>L-+,)X<=q>*._#j 7&&:u@u@u@u@b*b*b*b*7>7>b*p#N=&:},},},&-&-},&-&-},&-_#tO},_#_#_#_#_#&-_#&-^>==!+z,hOK=;*mOA#BOkX>+T,G#G##oC>C>(*C>V@{.{.j:{.V@j:{.V@V@#o,,6;F-z,6XE.s.@>),+Xm%m%P&+X -),4O*&6@@>d=t$ZOD+j:j:C>;O/-6 <@<@<@H,=<}#% A*}O#,.}Ogob@>++&/-T,G#V@j:W z%KoKo2#l.r r |$),L>+X' m%I++XP#l._=@@c#. M$[oY=@@, Q$T-, $+[%[%););u.u.4*_:_:iX9=co>$>$8-35o~#~#~#5o5o5oO-O-O-5o#=T@=X(&(&C:C:C:=XC:C:=XC:C:C:C:C:(&(&C:C:(&C:(&E+l$7&==a#,.goh&Q$d%{:>+T,G##o#oC>(*(*C>(*{.{.V@{.j:j:j:{.F&D+D+_=H,kOF.a#+$p:W |$I+m%l;P&G@ -),r 7+.:vX2#KoZOD+j:{.(*T,)$6 s.s.<@$+V ]@F-c#%*f+M$A:tOy+_#A;F.& #;/+G$ ", +" z$< b+!+-%y+_#*.a#-;L;0:0:}OL;V x>6 /-6 ;OG#{.j:D+z%t$0,vX6@*&`-),P#o=P&l;' P&G@;o@><@P*3%H%r&V 6;T-!=$OQ$$OT-$+$+[%[%);@@u.4*_:iX_:9=co>$8-8-3u@~OM;+.C:(&(&(&(&(&(&C:C:E+E++.M;M;M;M;+.M;+.+.+.+.+.+.+.+.M;M;+.M;M;+.+.M;+.M;b-^oTX+;M-Y:=+;O#o#o#oC>C>C>#o(*{.{.{.{.V@{.j:D+ZOt$ZOp;y=; r&j j F-$##o4OP&' m%v:+XL>4Or r .:u*0,t$eT,;O6 ';s.{:@@0:%*F-[o<=F.M-Q@j j &-H%C Ioo MX ", +" P%~;A>0*. &-&:tOA:_o-;%*)Xc+N,`+)X!=/->+/-;O_=C>D+D+z%Kod=d=@>*&`-4O;o+XP&l;l;P&G@P#2#w- @z,*.6X~%iXQ$A#!=H,H,H,, T-, [%$+u.4*u.4*_:iX_:9=%,co>$>$3$>$co>$co>$coco9=9=9=>$co%,coco%,co%,cococococo%,%,cococo%,co%,coco[%Y:b*7&M-%*+$6;A#w-7*>+)$G##oG##o#o(*(*(*V@{.{.{.{.z%e6Xa#j u@-;r:/-.:G@l;m%I+P&L>),|$r 6@2#0,Koe++&;O_=(*F&W z%u-2#2#u*.:r ),;oG@P&m%m%P&o= -KoV+3-. M-)Xh&, x>ooA#A#H,A#H,T-Q$, $+$+[%u.u.@@_:_:$#$#9=%,co>$8-mOH z@; 3-F-f+}&C.+.-%#om%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%kOl$j z,L;~:>$x>Cos.>+/-_=#oG#G#G#C>(*(*(*{.F&W W z%ZO,,3WXH$7*l.G@l;l;l;+XG@ -|$*&6@2#0,KoZOW F&V@G#_=6 ';s.';:#n#%*U%t>F-#H%N*}#[oc+)X%*Z$s>6 ';>+)$T,#oj:W ZOu-Ko2#@>*&r 4O;o+XI+l;l;P&+X),u-W*c+M-A==<%,A#W*x>oox>ooA#A#$OH,Q$T-$+[%[%);@@@@_:4*$#$#9=%,coco8-y%h&{X0.1;L;s@^>N=#=N,vXm%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%|$3%M;&-F.K=; _:p:y=s.6 /-_=#oG#G##oC>(*(*V@V@W z%)$Q$E.;*N,,.U%c#t>)X)XK=}O}#,Xu@M$0.y=u*G@I+m%' P&o=),`-*&6@2#0,t$z%W F&(*G#T,6 ';{:6 9<0.Y:}OA*,.3%A=}&+;y+&-A;b $oH+1@ ", +" $;.*R>*.tOy+&-*.WXhOU%L.L.% `+5=w-s.+&/-_=G#V@D+z%e),ZO!=t>. F.rX_:W*(.b@W*x>ooA#ooA#H,H,T-Q$, [%$+);u.@@4*4*iXiX$#$#%,co8-mOh&S,rX0:6XA=&-l$n#V `+}Ot>t>A*t>K=K=)XK=N,F-]>*.u@A;.#y=vXo=I+m%I+P& -4O|$*&u*2#d=u-e1;`+N,N,]@>:. ==j j Q@M$>O;&g% ", +" MXX-o#q>qo7&-%A:_o-;%*)X0:K=6XL.T-6 ';/-;OG#(*F&z%u-Kod=@>6@*&|$ -o=P&l;l;v:o=|$ZOQ$[o. b @u.W*v&b@b@b@b@W*oox>ooooH,Q$$O, $+$+[%[%@@u._:iXiX$#$#%,>$8-y%h&S,rXh@,-}&b*M;T@>+m%m%m%4OKoKoKod=0,0,d=d=2#d=0,2#d=2#2#2#vX2#2#2#2#2#vX2#vX@>@>u*2#l.v:m%m%m%n#y+b**.<=3-H H,9<{:6 /-;OT,T,_=_=#oz%ZOs., co5=Z$F-A*0:h@h@A*A*t>c#K=c#c#c#N,}O<=H%u@}&+,Cod=;o' m%' +XP#4Or *&vX@>d=t$ZOW V@#o_=)$>+<@7*<@coN,L;N,% ioq>H%^>y+-%}&A=-;p*E, ", +" >*<+OXI&+;7&^>. s@<=N,c+K=Y:Z$co)$';/-)$T,(*j:p;eP&l;l;P&L>4Oe<, }O. }#; [%b@v&V+v&v&b@(.W*x>ooA#ooH,H,$O, , [%$+[%);@@_:4*iX_:$#9=>$39%]>a#A:7>M;*.p;m%m%I+{.v&e;d%9Co<@>+)$T,)$_=W 0,G#A#u.s>h@F-t>a&c+0:0:h@A*t>t>A*t>)X)X)Xc#K=[o% <=. 7&A:=<5$2#L>I+l;' G@P#),r l.6@vX0,u-ZOF&{.C>_=T,>+<@>+w-H$%*`+)XL;hOA=}&tOy+qoH%f+w#C@-=P% ", +" u<1 M M-},y+},}&A=3%% 0:)X,.%*{X<@6 6 ;OT,C>V@F&eooooA#!=H,Q$Q$, , $+$+[%u.4*4*4*_:9=9=4*_:E.5==+.&-N*[o~%%,p:y=s.+&6 {.ZOj:CoT-mO9%c#t>c+a&0:0:a&0:0:L.h@t>A*A*A*)X)Xc#K=c#K=N,% ]@M$y+^>9%CovXo=I+m%I+L> -4O`-.:@>Kot$u-p;F&{.G#_=/-';{:>+p:+$]@U%)X%*F.M-Q@y++;A:_op** ", +" Zo] r&Q@y++;,XM$b Y:A*L.F-io+,p:6 >+/-_=G#j:F&p;t$0,d=u**&r -;o+X' m%v:L>),z%Q$% M-%*s>!=U e;d%U V+U v&v&(.b@x>x>ooA#ooH,Q$Q$, , [%[%[%u.u._:4*);[%iXP*; ; 5=V kOt>-;}&l$#=$+P&m%m%2#Cov&e;e;d%d%d%BO9t>)X)Xc#c#c#K=[oF-6X_o7&qo+,,,6@G@l;' v:L> -`-*&l.vX0,Koz%D+j:(*G#)$6 s.{:';T-h@Y:[o}O,-s@A;&-y+},*.N*i>A$poI ", +" -XF*B$H%+;7&qo`OF.]@N,V Z$6X)X4*>+>+/-T,G#(*D+z%ZO0,2#6@7+`-4OL>v:l;m%l;v: -u-A#N,. ]@P*x>d%BOd%BOU V+U U V+p:(.W*x>x>A#x>H,H,Q$Q$T-$+[%[%@@u., [%y%z@z@X+rXh&%,{X.#Z$s@_#M;l)Xc#c#N,c#K=Z$[oZ$]@_oy+}&;*kX*&v:l;m%v:P#),`-*&l.2#0,u-z%D+{.C>_=)$+&7*';:#3#%#&-&:-%!+a##+>+;OG#(*j:z%ed=b@h@M-}#Y=x>w-w-9<9H,H,$O$O, [%T-H,$O_:y%H S, @{X@@, [%$#n#=V+e;BOBOw-w-w-5$5$5$CoCoCoy=,,kXkXy=:#kX7*{:{:7*7*<@<@s.y=C>G@m%m%m%]@A%j _o`+ @4*(.x>b@u.3-h@V V c+9%3-=<1;1;1;V V a&L.0:a&0:0:h@h@A*A*A*t>)Xc#)XN,K=K=N,Z$[oZ$6XM-&:H%X++&r I+m%l;G@L>P#`-r @>2#Koe+7*>+9<.#Y:% K=Y:>:M-qo+;-%!+IO9Ov#,OP% ", +" ;=U&1,}&j y+==M$r&Y:A*c+}O]@ @V+/-+&6 G#C>j:D+e+e;d%BO9<9:)X0.8-cogoh@V c+a&9%go+$3-kOkO9%1;1;V V V a&a&a&a&0:L.h@h@A*A*t>t>t>t>c#N,N,K=Z$Z$[oF-<=`OC.z,Y=;O|$' m%I+v:L>),|$l.u*d=u-u-W {.(*_=T,/-';<@s.A#h@]@c#F-,-WX*.tO7&^>`Os@_&boc. ", +" q@Z P=0+},y+_#H%s@io[o0:A*U%L;u.s.>+/-T,C>V@D+p;KoKo2#6@7+4OP#o=P&l;I+P&;o@>w-3-M$b OA#w-CoCoCo5$w-BOBOd%e;U U p:(.(.b@x>x>A#ooooA#H,[%@@3<~%;*H @@[%A#(.W*$O[%$#h&;*N,r&,XA%A%!=' m%m%0,{:9A*A*t>)X)XK=[o[oN,[oN,N,% <=A;b*>:h&#o;o' l;' +XP#|$7+.:u*0,u-ZOW {.(*G#;O6 <@s.:#{XZ$U%K=L;-;_o==+;+;,Xz,-;o@:&O> ", +" ^%^@S>Uo^>j -%Q@z,hOL;0:0:,.%*h&,,>+>+;OG#V@j:p;ZOKo0,u**&`- -L>+X' m%I+o=*&<@;*M-s@L-!=9<,,,,,,CoCo5$5$w-BOe;U U V+v&(.b@b@x>W*oooo!=Q$z@+,s>u.iX, x>x>H,!=!=$O[%9=P*+$U%q>&-=XC.;Om%m%m%D+w-9+7*C>;om%m%G@rXp#7&^>,XWX<=}O)XkOgo+,go+$+$3-=<=<=)X)Xc#K=N,[oN,N,N,[o}O}#}&C.# -),7+l.2#t$u-z%F&{.G#T,)$+&<@{:9<1;]>c#K=<=>:H%&-y+&-A;6>9,[ y, ", +" G$ &GXM-tOy+qo`Os@6Xc#L.[o}OA*oo+&>+)$_=C>{.D+ZOt$d=2#.:`-P#;oG@P&l;P&G@`-C>r:z,_o @!=5$:#:#:#,,Co,,Co9<9<9(.v&y%;* O8-_:@@A#!=!=H,H,$O$OH,$Ou.3< O1;6XM$7&E+r&z%m%m%' G#9<5$5$,,,,Coy=y=:#:#:#kXkX{:{:{:7*<@<@';s.s.s.';+&+&>+6 {:j:+Xm%m% -hO#=s,-%*.F.,.0:=<=<3-+$+,+$+$3-=<=<=A*)Xc#c#c#K=[o[o[o[o[oZ$U%#<,XC.`+b@2#+X' ' G@L>L>|$*&@>2#Koeu*7+),L>G@P&m%I+G@P#0,[%,-M$1;T-5$kXkX:#y=y=y=y=,,w-5$9$co[%!=$O$OQ$$OH,H,H,$OQ$, _:M+Q;h@,-*.s,b-+$*&m%m%),6 5$,,,,,,y=y=:#:#:#{:kX7*{:7*7*<@s.s.';s.>+';+&+&+&>+6 6 +&t$I+m%m%p;^>5op#qoz,}#F-0:kO+,3-3-go+$+$+$3-=<=)X)Xc#c#K=N,[oN,Z$Z$Z$L;b },tOa&';r +Xl;' +Xo= -`-6@@>d=t$ZOW {.#oT,)$6 7*{:{: @`+[oN,]@F.A;_#y+},A;6>,*1.9 ", +" NXb+. j y+^>`Os@6Xh@L.U%U% @e;+&6 )$_=(*D+z%e+>+6 /->+6 /-+&T,.:l;m%l;!=b*(&&:,XWX]>N,c+=)X)Xc#c#K=K=[o[o[o[o[oZ$`+WXy+H%S,V@ -l;l;P&+X;o),7+l.@>d=u-ZOD+V@#o;O/-+&7*7*A#1;]>Z$Z$-;z,}&},j ==M-%>- d$c, ", +" 8#H&X*8%_#y+-%}&z,-;% c+A*Y:U%Q$<@+&/-)$#oV@W z%Ko2#@>.:7+),;o+X' l;v:o=.:+&X+_o}#h&w-<@<@<@<@7*{:kX:#,,Co,,5$d%Co:#{:$+{XE.mOM+>$$+$+$+$+$+[%[%T-T-T-Q$$OH,$OQ$Q$$+con#3-,.WX&-~#-%_=m%m%m%F&y=,,kXkXkX{:{:7*7*7*<@<@';';s.s.+&+&>+>+6 /-6 6 /-)$)$;O+&{. -m%m%),+,A%~Oj *.r&%*c#1;3-go5=go+,+,+$+$go+$3-=F.);e+<@kXs.z@[oF-F-6X>:. qo7&},*.f$y&v>o. ", +" T=N-H%y+j ^>. F.Y:A*A*%*}On#y=+&6 ;OT,(*j:p;e`-V@6;q>N*Q;V+s.s.s.';s.{:{:{::#,,Coy=s.>+b@8-8-mOs>h&u.[%[%[%[%[%$+, $+, , Q$Q$Q$Q$H,$OT-[%4*y%X+a&<=M$&:#=-;ZOm%l;' #o,,kX{:{:{:7*7*s.<@s.s.s.s.s.';+&>+>+>+6 6 /-/-)$/-/-;O_=';z%P&m%m%vXr&5oN=&-. hOU%h@9%gogo+,+,+,gogo+$go3-3-=<=)$6 ';7*<@BO.#]>% N,#,-% 0:t>]@t>v&/-';;O_=#oV@W e*&`-4OG@v:' l;v:4Oz%u.]>. 9%A#';+&+&+&';s.7*7*kXkXs.+&kX$+$#>${X{X%,[%u.u.);[%);[%[%, T-$+$+, Q$Q$T-Q$!=$O, );$#r: @c#3%A;^ol<~:7+m%m%4O)$y=kX7*{:7*<@<@<@s.s.+&';s.';>+>+/-6 >+/-/-)$;O;O;OT,T,_=/-d=m%m%m%;OtO~#u@^>A=]>[oa&3-5=5=.#5=gogo+$+$+$+$kO3-3-kOkO9%9%1;1;V V c+0:a&a&0:0:h@A*L.h@A*t>c#c#)Xc#K=N,N,F-U%%*)X.#8-T-iXL.z,a&kX7+' m%I++XP#`-*&u*2#Koey+&-*.EoO+-M$b `+A*A*L;F-s>kX+&6 T,_={.F&p;t$0,@>6@r 4O;oG@I+l;I+L>2#U a&M-)X@@{:/-6 6 >++&s.7*s.)$';p:, $+z@~%mO@@u.@@);u.4*u.u.);[%[%, $+, $+, , Q$T-Q$Q$$OT-u.8-s>+,% F.,XT@&:(.l;m%m%2#+&:#{:7*<@7*<@s.s.s.s.+&';+&+&>+>+6 6 6 /-)$;O;O)$_=_=T,T,V@`-m%m%m%@@^o=Xy+A:s@Y:t>1;3-+,5=.#.#go+,go+$go3-3-=<=A*A*t>c#)Xc#K=F-}ON,a&s>u.,,W u-6 %,Y:z,H$G#;ol;l;P&L>4Or .:u*2#Koe_o1+u,7$ ", +" 8#q%J$n@_#7&-%!+q>,-F-c+c#}#0:d%;O+&)$_=C>j:W e7+>+; q>`+6;y=/-6 /-6 >+6 /-/-y=p:H,y%L-P*$#@@@@4*4*4*u.@@u.@@u.[%[%[%[%, $+$+$+T-Q$T-T-, Q$Q$@@mO O9%`+a#&-#%A;V@m%m%m%j:{:s.7*<@';<@s.';';';';';>+>+>+6 6 /-/-)$;O)$;OT,T,T,_=_=)$z%o=m%m%.:c++.l}##d=0,ZOD+{._=;O6 +&kX_=co}OU%c#6Xr&. qo&:tOH%Eo/O@.L, ", +" $;+:j=S;+;j ^>. >:Y:t>h@% }OL-kX;O6 T,G#(*D+ZOu-Kou*.:`- -;ov:l;' v: -D+iX]>_oL-e;/-;O6 6 )$;Os.5$w-[%; ~%>$u._:iX_:_:@@_:_:@@@@u.@@@@[%[%[%[%$+$+$+$+T-Q$Q$T-T-Q$, _:M+~%h@}#. &:T>L;d=m%m%I+T,7*<@<@';s.s.+&';+&>+>+>+6 6 6 /-/-)$;O)$T,T,T,_=_=_=G#G#T,d=l;m%m%V@A=5oTXqoz,,-% a&3-5=5=5=.#5=5=gogogo+$+$+$3-=<=<=+s.';U L-U%L;F-}#WX!+-%+;Q@_ov./OW. ", +" A+w*|:E>&:-%!+WX}#Z$V K=}#=s>X+h&iXiX$#iX_:_:iX_:_:_:_:@@u.@@u.u.$+[%[%[%$+, , $+$+, Q$T-$+$+[%$#P*.#N,-;!+~Ol$S,),m%m%4O)$7*';s.+&';+&+&>+>+6 6 6 /-)$/-;O;O;O;O;OT,_=_=#o#o#oC>#oC>.:m%m%m%,,&:~#7&A:WXioN,V go.#5=.#5=.#.#+,gogogogo3-3-=<=a&+$X+p:e++&:#/-9=`+,.t>]@F.`O^>7&},H%z*r+)$G#C>W ZOu-0,@>*&r P#G@v:m%l;P&),#oz@-;,->$kXT,_=;O;OkX%,Q;z@coco9=9=9=9=9=$#_:iX_:@@4*_:_:4*u.u.@@@@[%$+[%[%[%$+$+$+$+T-T-Q$$+@@>$Y==+<@';+&>+>+>+>+6 6 /-/-/-)$;O;OT,T,T,_=G#_=G##o#oC>#o#o#oD+4Om%m%m%8-A%C:j !+F.Y:)X9%+,5=5=rXrX5=.#+,gogogo+$go3-=<3-=<=+W D+j:F&D+D+D+D+D+D+W W D+D+(*y=Y=}#,.Q$u*l;m%P&o=;or *&6@2#Koe+<@';b@ @% % U%hOa#A:+;-%A:a#yO+O/% ", +" m@6OT%,Xj j ,XA=hOU%L.c#]>3-b@+&>+)$G#C>F&D+u-t$d=l.r 4O;oo=I+I+v:;o2#W*}OM$0.V+)$V@_=!={XS,H >$8-cococo9=9=9=9=iX_:iXiX_:_:4*_:@@u.u.u.u.[%[%[%);[%, , $+$+T-T-, $+4*y%L-V Y:A=_#.;q>W m%m%' W +&+&>++&>+>+/-6 /-/-/-;O)$T,T,;O;O_=_=#oG##oC>C>(*(*(*(*C>t$G@m%m%u*L.(&l),`-*&vX0,t$p;F&V@C>_=6 ';{:s.%,Y:6Xt><=s@H%},j qo. F.^;&OP% ", +" ^%6=R-A=&-C.},. >:]@c#a&K=<=0.y=/-6 T,_=V@p;ZOt$d=@>.:`-P#o=v:m%P&G@|$6 ~%-;c#$O;Oy=>${Xy%3$>$%,9=9=9=9=$#iXiX4*4*_:_:4*4*_:@@u.4*u.[%[%[%[%$+$+$+, $+T-, [%$#H Q;A*,-H%&:5oN,6@m%m%P&G#s.>+6 6 6 6 /-/-)$)$;OT,T,_=_=_=_=G#G#C>#o#oC>(*V@V@V@j:(*@>m%m%m%;OWXT>N=qoz,,-F-c+3-5=rX~:.#rXrX5=5=+,gogo+,go+$+$3-=N,+$@@s.)$(*{.V@V@j:{.{.j:j:D+j:j:D+D+W z%W D+D+j:';y%iof+cod=v:m%' +XP#|$7+@>0,0,e+oo3-% F-,.3%z,Q@7&+;!+q>X;a+)$T,#oj:p;z%u-d=u*7+4O;oo=P&' G@o=t$$+]@b s>mOy%6;M+r:6;>$co>$>$cococo>$co9=9=$#$#iXiXiX_:_:4*_:iX@@u.u.u.u.);$+[%[%[%$+, , $+, $+@@coz@.#Z$r&!+l$l${XP#m%m%4O_=+&6 /-)$6 /-;O;OT,T,T,_=_=G#G##oG##o#oC>C>(*V@{.j:{.{.j:j:r m%m%m%p:b*T>&:,XN*]@K=V go.#rXrX.#rXrX5=5=.#+,+,+,+$+$+$=<3-=V@{.j:{.j:D+D+D+F&D+W z%W W F&F&{.9<.#a#0:,,4Om%l;v:L>4Or *&vXKou-p;D+(*T,;O6 s.7*:#%,,.Y:K=ioq>*.tOy+^>z,-;aXt ", +" H:o;f+==7&tO*.q>]@)Xc+N,}#~%kX6 6 T,G#V@F&p;u-0,@>.:r -o=G@m%P&G@),';kO. hOX+E.{Xh&mO>$mOmO3<>$8->$co>$>$co9=$#9=9=iXiXiXiX_:_:4*_:_:u.u.u.u.);[%[%[%[%$+$+$+, , [%iXmOn#=<`+WX^>T@Q@BOm%m%l;vX)$6 6 /-;O/-;OT,T,T,G#_=G##oG#C>C>#oC>C>C>V@V@{.j:F&F&j:j:eG#C>(*(*C>(*V@{.j:j:j:j:D+F&j:F&F&p;z%p;D+j:D+G#[%,.z,{Xu-v:m%I+o=P#`-r l.0,KoZOW {.G#T,/->+{:>+W*A*F-)X`+f+M-==y+-%H%s@I#lOG$ ", +" @%F;H@. tO7&^>M-b ,.L.A*U%t>$#s./-6 _=(*j:D+e$>$>$8->$>$>$>$co9=$#9=9=$#iX_:iXiX_:_:4*_:u.4*@@u.u.);[%$+[%[%, , [%[%);$#H X+0:]>M--%t+##o#o(*(*(*V@V@V@{.j:F&F&j:F&D+F&2#P&m%m%0,N,=Xl<&-M$,-F-0:=<5=;*;*~:;*rXrX.#.#5=5=go5=go+$+$3-kO=C>#o(*(*(*V@{.j:{.{.{.D+D+j:F&D+D+p;z%p;W W D++&n#N*% U 4Om%l;v:o=4Or 7+@>0,e{;A:j -%A:a#ioN,L.F-]>X+w-+&6 ;OG#{.D+z%e.:r -G@P&l;v:G@|$<@1;*.-;X+6;h&H mO3$>$8->$co>$>$co%,9=9=9=9=iX_:_:_:4*_:_:_:_:@@u.u.u.);$+$+[%[%$+$+$+$+);%,E. @t>hO*.C.[,1; -m%m%o=#o6 T,;O)$T,;OT,G#_=_=#o#o(*C>#o(*(*(*V@V@V@{.j:F&F&F&F&F&D+*&m%m%m%:#H%#=TXQ@WX]@N,V go.#;*;*;*~:.#.#.#5=5=+,gogo+,+$3-+$c+K=0: OcoQ$T,0,j:G#)$T,G#G#G#G#G##o(*C>(*V@j:{.{.{.{.D+D+F&F&D+D+z%p;z%z%W p;j:b@A*A=; ZOv:l;I+G@;o|$.:6@d=t$ZOW j:#o_=/-+&{:7*(.% Y:c#%*F.A;&-j _#. b D>`& ", +" Y&6o>:_#7&&-H%F.Y:A*c+F-]@z@';/-6 ;OC>{.D+ZOt$d=u*.:|$;oG@' l;G@;oKo[%s@`Oa&P*H h&H mOmO3$>$>$co>$co>$co9=9=9=9=iXiX_:iX4*4*4*_:4*u.u.u.@@);[%[%, [%$+, [%);4*8-s>+,}OF.Q@b-TXmOv:m%m%`-_=6 T,T,T,_=_=_=G#G#G##oC>C>(*(*V@V@{.{.j:j:j:j:F&D+D+D+W z%4Om%m%m%$+l$T@7&!+r&`+t>kO.#rX;*;*;*;*~:rX.#5=5=.#gogogo=(*(*(*C>V@{.{.j:{.j:D+D+D+F&D+p;p;W W W z%p;>+Y=a#F-9<|$l;' +Xo= -`-6@vXt$eh<2+Vo ", +" 9&_>7O`OtO&:==_o3%L;L.A*% c+);';6 )$G#(*{.W ZOKo2#u*r 4O;ov:l;P&G@7+s.go*.r&~%M+M+H M+H y%3$8->$8-8->$>$%,9=9=9=$#iXiXiXiX_:_:_:4*_:4*u.@@u.@@);$+[%[%[%$+[%u.$#y%S,kO6XA=_#T>H%kXm%m%P&vXG#;OT,_=_=#oG#G#G#C>C>(*(*(*V@V@j:{.j:F&j:F&W F&W W W p;z%0,L>m%m%I+n#T>+.tO`O3%}Oh@3-rX~:;*;*;*~:;*rX.#rX.#5=.#9%L.+$ OY=$+p;u-C>)$/-;O;OT,;OT,;OT,G#G#G#G#C>(*(*C>C>V@{.{.{.{.j:D+F&D+D+D+W p;z%W p;D+z%j:A#t>f+Y=z%G@' I+G@;o),.:u*2#u-z%F&{.#o)$>++&{:Co@@N,U%F-<=WX}&+;y+A:_o.<'$}$P% ", +" P%%&R%{ A:+;+;}&q>]>K=a&% <=s>{:+&>+T,#oV@D+p;t$d=vX*&4O -L>I+m%v:;ou-, r&M-)X{XM+H M+6;M+6;mOmOmO3<>$>$8-8-cocococo%,9=9=9=9=iX_:iXiXiX_:4*_:_:);u.u.@@);[%[%$+$+, );@@%,h&; c+hOA:&:@:6Xl.m%m%+Xz%T,_=_=G##oC>C>#o#o(*(*V@V@V@{.{.j:j:F&F&D+D+p;p;W z%z%p;p;6@I+m%m%t$}O=Xl$qoz,]>Z$c+go.#;* @ @;*;*;*rXrXrX+,1;kO~:~%mO+&z%C>>+>+)$)$/-)$T,T,T,T,;OT,G##o#oG##oC>(*(*(*(*V@{.j:{.j:F&D+D+D+F&p;ZOz%W W D+z%p;<@; _o% y=`-l;m%+X;o -r 6@@>KoeT,;O>+7*kXU K=Y:c#`+>:H%_#+;_#`O>:w#;<8# ", +" |OU#q>},7&},H%F.6XA*a&% ]@M++&+&/-T,#oF&p;ZOKod=6@r ), -v:l;l;o=7+6 Q;}&>:~:r:H H H 6;6;6;y%mOmOmO8->$>$>$cococo>$co9=9=9=9=$#iXiXiXiX_:_:_:4*@@u.u.u.u.[%[%[%$+););u.$#z@kO%*A=j l<.;~:' m%m%L>V@;O#o#oC>C>(*(*(*(*{.V@V@{.{.F&F&D+D+F&W W p;p;z%z%z%z%z%ZO|$m%m%m%Co!+=X7>,XN*]@c#9%5= @;*;* @ @ @0.;*9%1;.#+,0.(.z%T,/->+/-6 6 )$;O)$;O)$;OT,T,;OT,G##oG#G##oC>C>C>(*(*{.j:{.{.{.{.F&D+F&D+D+W p;z%p;D+D+p;V@$+}O3%H u-P&m%' L>),`-.:2#0,t$z%W V@G#;O>+<@kXd%.#F-c#}O3%_o,X-%+;*.q>:.a:uoP% ", +" Y _ob L;A*)XF-3-, +&>+/-_=(*D+z%t$KovX*&r ),L>P&l;v: -u-H,hO`O[o Oh&M+M+6;H 6;6;mOmOy%mO3<>$>$>$>$>$cococo%,9=9=9=9=iX_:_:iX_:4*_:_:_:u.u.u.u.);[%[%$+Q$$+mOP*;*]@`OA;^>l$7>9=m%m%m%4O(*T,C>C>(*(*V@V@V@V@j:j:j:F&F&D+D+W W W p;z%z%ZOz%ZOe+6 6 6 6 /-/-)$;O)$;OT,;O;OT,T,_=G#G#G#G#C>C>(*C>{.{.{.{.{.j:D+D+D+D+F&W p;p;p;W D+ZOp;:#0._oK=7*|$' l;P&;o`-*&6@0,t$e+';{:CoT-)X%*% <=q>}&j 7&Q@A=W,uO}$i= ", +" 7o'&f+==-%-%A:A=}#N,L.U%6Xr:{:s.6 ;OG#V@W eG@I+l;G@r T,Y=A:s@+,z@M+M+M+H 6;6;6;6;y%3<3$8-8-8-coco8-co9=9=9=9=iX_:iXiXiX4*_:4*4*u.@@@@u.[%Q$H,u.>$mOQ;Z$[oL.6XM$-%=Xz,{:m%m%' 6@#oG#(*(*{.V@V@j:{.j:F&F&F&D+j:W W p;W p;z%e+6 >++&';+&6 >+6 6 /-)$;O)$)$)$;OT,;OT,T,G#G#G#G##o(*(*(*(*C>V@j:{.{.{.j:D+D+D+D+W z%p;z%z%p;z%z%#o_:]@hO%,u-I+m%P&L>),7+l.vX0,u-p;{.(*G#/-';7*y=9]@N,%*r&`O},y+qo. r&D>(=cX ", +" P%+-~@N*&-j &-A;s@6Xt>0:L;6Xco;O';/-T,C>{.p;el.r P#;o+X' P&L>vXv&F-. L;; M+M+M+M+M+6;6;6;6;y%3$>$>$>$co%,%,co%,9=9=9=iXiX$#$#_:@@4*_:_:@@@@$+T-@@9=iXr:0:9%E.s>~:L.}#*.&:.;N,r m%m%+Xu-#oC>V@V@j:{.j:F&F&F&D+D+F&p;W p;p;z%z%ZOZOe+/-6 <@s.';';';+&>+6 6 6 6 )$)$;O;O)$T,T,T,;O;O_=G#G#G#G#C>(*C>C>(*j:j:{.V@{.j:D+D+D+D+F&p;p;p;W W F&p;z%kXX+s@V )$P#m%I+o=P#`-.:6@d=e}O-;M-^>j tO!+q>3:`XY ", +" ^%q+/@`O-%7&==M$b L;h@)XF-gooo6 ';)$_=(*j:z%u-d=@>l.`-),;ol;l;P&P#F&8-. q>V {Xr:r:M+6;H 6;6;y%6;6;mO3$>$8->$>$co%,>$co9=9=9=$#iXiXiXiX_:@@4*@@[%);$#%,M+~:3-P*>$mOcoH @[o>:Q@TXO-S,m%m%m%P#F&C>{.{.{.F&F&D+D+W D+p;W W z%z%z%ZOZOe,XN*%*L.a&9%.#L.K=r:V+V+kX/-)$s.<@s.<@s.+&';+&';>+6 6 /-6 /-)$;O)$;O;OT,T,T,T,T,_=#oG#G##o(*C>#o(*(*(*{.{.{.V@F&D+D+D+j:W p;p;p;z%u-d=u-)$y%z,#;O/-<@{:y=x>a&`+U%]>a#}&tOy+,XA=m*9#BX ", +" h 2.jo}&+;j }&a#}#N,h@L;U%3<';';>+T,G#V@D+e}# @z@z@h&H 6;H H 6;y%6;6;mO3$>$>$cococo>$co%,9=9=9=$#_:iX_:iX);@@iX9=$#Q;1;n#$#3<@@ooT->$S,3-L;WX},b-&:T-m%m%m%`-V@(*{.j:j:D+D+D+W W W z%p;z%z%ZOz%em%m%m%>$C:M;y+A;>:%*t>N,L;0.iX$+BOT,/-{::#kX<@s.7*s.<@s.+&+&';+&6 6 /-6 6 6 )$;O)$;OT,T,T,T,T,_=G#G##oG#C>(*C>(*(*(*{.{.j:V@V@j:D+D+F&F&p;t$Kou-ZOD+d%r:N,qoH%P*F&P&m%I+L>),r l.@>Kou-z%F&(*T,/-s.7*y={:a&]>% `+>:H%&-y+==M->>z Z:P% ", +" [O* o:qoj &-H%N*6Xh@0:6X]@$#_=';)$T,#o{.p;t$0,2#6@r 4Oo=I+I+P&G@2#Q$]@`OK= Or:E.h&H M+H H 6;6;6;6;y%3<3$8->$>$cocococo%,9=9=9=9=iX@@4*_:$#9=s>+,; M+y%@@v&V+H,@@iXmO; a&]@M$y+(&r&T,m%m%' 6@{.V@j:F&F&D+D+D+p;p;p;p;z%z%ZOZOZOu-e(*(*(*(*j:{.{.j:V@j:D+D+p;ZOZOe++^# ", +" 8#t-@oA=-%j ==M-r&L;0:L.,.[o);_=+&/-_=(*F&p;u-0,vXl.`-),G@I+I+v:4O(*n#A:r&3-s>h&h&r:M+M+M+H H 6;6;H y%3$8-8-co>$co>$co%,9=9=$#$#$#_:_:mO5= @mOh&>$b@w-(.$O$OT-[%%,M+Q;t>3%!+b*O-1;;om%m%o=Koj:F&D+D+W W W W z%ZOZOz%el$C.A:<=0:~%Q$BOV+ooooW*v&BO9<5$y=:#{:<@<@<@';+&+&';>++&/-6 /-/-6 /-)$)$)$T,T,T,T,T,T,_=#oG#G#_=G#(*C>(*(*{.{.j:j:j:j:p;z%z%ZOC>W*6;Q;[oY:%*% }Os@b*N*, d=I+m%+XP#|$7+u*vX0,e+s.:#kXcoh@F-% ,-z,A:+;+;}&A=s:3,|- ", +" .&}.8o. +;7&,Xz,hO% 0:K=Z$X+U /->+;O#oV@W ZOKod=6@*&|$ -+Xl;l;v:*&w-0:^>6X @P*r:h&h&h&H H H M+6;6;H H mO3$>$>$>$co>$coco9=9=$#@@>$; ~:n#h&H W*d%e;x>!=!=A#H,Q$[%>$z@rXZ$s@==N=T@6;m%m%m%;op;{.D+D+p;W p;z%p;z%ZOZOZOe;om%m%m%(.+;T>N===F.0:z@%,8-co9=_:4*u.$+oop:U 9<5$:#{:<@7*<@';+&+&+&+&6 /-6 6 6 )$;O;O;O)$;OT,T,;OT,_=G#G#G#_=G#C>C>(*C>(*j:j:{.j:F&u-u-:#cos>c+L;]@}O[oN,[oF-,-},A: O#o+Xm%P&L>),7+6@vX0,t$z%j:#o_=6 ';kX:#d%3-%*}O]@WX!+},&:==_o3:p-=* ", +" q@M,Yo!+y+y+}&WX}#N,L.L;Z$9=';';6 T,C>j:W el.r ),L>v:m%l;G@0,4*3%M$)XL-z@r:h&r:h&H M+H H 6;H y%6;y%3$8->$>$8->$>$9=_:@@{XrXY=6;z@4*CoBO(.ooooooA#A#A#H,, );8-Y=3-`+A=},b-+;b@m%m%m%|$W j:p;W p;z%z%ZOZOZOZOu-e@>vXl.+Xm%m%m%6;5o(&7&a#,.a&5=~%H$Y= OS,{Xr:y%$#, A#(.d%5$kX7*7*<@<@+&+&+&+&+&6 /-6 /-)$;O;O)$)$;OT,T,;OT,T,_=#oG##oG##oC>(*C>(*V@{.ZO0,/-!=8- @}O,.U%c#N,[o[o[o[o[o%*M--%% w-),m%I+o=P#r .:vXd=t$z%D+V@_=/->+<@:#{:3-]>% ,.F.H%&-7&_#. I;$%]- ", +" L,sXk;^>y+},H%s@]@t>L.<=`+[%#o';)$T,C>F&z%u-Kou*l.r ),L>I+l;P&P##oX+Q@b +$S,z@r:h&E.h&h&H H H H H y%y%6;y%3<3$>$8-8-_:4*E.~: Oz@Y=$#BOw-U (.(.b@W*x>x>A#x>!=$O);@@3< O1;6XM$7&+.3%C>m%m%I+l.W D+z%z%z%ZOe6@@>r v:m%m%v:3-@:l$-%H%-;U%t>a&c+c+c+a&1;+$ @S,6;_:$O(.d%y=kX<@';s.';+&+&+&>+6 /-6 6 6 /-;O)$)$)$;OT,;OT,;OT,G#G##oG#C>(*C>(*p;t$t$V+[%{X0:,.U%c#c#c#c#K=N,Z$N,N,N,% f+y+q>4*d=' l;v:P#|$7+6@2#Koej:z%Kod=@>*&|$ -L>l;l;+Xr ,,L.qo`+Q;{XP*E.h&r:r:r:H H H H 6;6;6;6;y%3<3$$#4*3<; X+E.Y=z@x>5$BOU V+v&v&p:b@b@x>x>x>x>!=$O[%iXy%~%A*ioH%TX5ogoL>m%m%o=0,p;p;z%e@>@>u*6@6@l.),' m%m%D+-;.;l<7&Q@A=-;]>6X]>}#ioio]@Y:% c+ @E.iXQ$p:w-:#7*s.s.';>++&';+&6 6 6 6 6 6 )$;O)$)$T,T,T,T,;O;OG#G#G#_=_=j:2#u-:#$Ou.+$[o% c#)Xc#)X)XK=c#c#N,Z$N,[oN,Z$io&-!+ OC>v:m%P&L>),r l.2#d=u-W V@#oT,6 s.7*7*M+K=[o[o# ", +" v (On>. +;j ,Xz,3%}O0:c#Z$;*v&T,+&)$_=V@D+ZOt$2#u*7+4O;oG@l;m%+X@>T-Y:H%)X; s>P*E.r:E.h&h&M+H H H H 6;6;6;6;mO3<>$4*8-S,L-P*Y=n#!=9x>A#A#H,$+9=r:~:[of+,Xl$=X8-m%m%m%P#u-z%ZOeu*u*6@6@l.l.6@*&o=m%m%m%!=7&~#M;TX-%A:`OM$M$. `OH%,X7&^>r&]@)X~:r:_:ooBO:#{:7*7*s.+&+&';';';>+/-/->+>+/-;O;O;O)$)$T,;OT,T,_=T,(*e% )Xt>)X)X)X)Xc#)XK=c#K=K=[oN,[o[oZ$Y:`O-%N,:#o=m%P&o= -r l.vXd=t$z%{.G#_=/-+&{:kX(.+,,.}O]>q>*.},7&,XA=~ T:T& ", +" .&ao#$!+j j *.WX}#[oA*,.N,%,<@>+6 T,#oj:p;u-KovX.:`-),o=P&' ' o=eooooA#$O);>${XgoU%q>},A%},(.m%m%m%4OZOZOu-ZOu-t$Ko0,Kod=d=d=2#2#d=vXvX@>@>@>6@@>6@l.l.l..:.:.:7+P&m%m%m%Y=a 5oE+l++&>+/-6 6 6 /-;O)$)$/-)$;O;O;O;OD+2#V@5$U 8-a&N,)XA*K=t>h@A*t>t>)X)Xc#)XK=K=K=[o[o[o[o[o}O>:u@q>!=4Om%I+G@ -|$*&u*2#t$z%F&C>G#;O+&7*kX:#~:,-U%%*F.. &-&:qoM-T%1O_*P% ", +" %o4+s A:+;-%H%s@]@t>h@<=% Q$#o';/-T,#oj:z%e7+`- -+X' l;P& -_=goqo}#~:{XP*z@P*r:r:r:r:M+H H H H y%8-8-E. Os>{X @H U Cow-:#:#9x>H,T-@@3< O9%6X_o7&E+}#{.m%m%I+.:z%u-t$evXvXu*u*6@6@6@.:l.l.*&.:.:4OI+m%m%;oc#s<~#=XE+~Ol$l<=XO-T@TXH%L.y=ZO.#tON*% +,h&);(.5$kX7*7*<@s.+&';>++&>+6 6 6 6 /-;O;O)$)$/-)$V@z%z%kX5$u.rXc#N,A*t>h@L.L.h@A*t>A*A*t>)X)X)XK=c#c#N,Z$[oN,[oZ$}#7&A:y%0,I+l;v:;o),r l.2#t$z%D+V@_=;O6 s.{:7* @}#}O}Or&M$qo7&&-A;>:K$^ !% ", +" f*0 dX^>+;&-. >:`+h@h@<=F-H,C>';/-_=C>F&p;e*&4OP#G@l;l;v:*&w-[o&-}O; {Xs>z@P*z@r:E.r:h&M+H 6;y%H s>{X{XX+n#Q$9A#$O, 4*y%~%h@,-A;N=T@;*G@m%m%G@@>u-t$t$t$Ko0,0,0,d=2#2#2#2#@>vXu*@>@>6@6@l.7+l.l.l..:*&.:7+L>' m%m%)$M$x=~#5oT>[,.;O-E+&:<=>$G#@>m%C>-;u@M$Y:=+CoBO Ot>)Xh@c#t>c+c+0:L.L.h@A*h@A*t>)Xt>)Xc#c#c#K=N,[oZ$[o[o[oY:^>qorX_=v:m%v:o= -`-l.vX0,e%}> ", +" P%/#',a#},j qoM-b L;0:t>L;=<(.G#>+)$#oV@D+p;t$2#u*7+),o=+Xl;I+v:vX);}#H%h@ O{XP*z@P*P*z@r:h&r:H H r:E.z@~%X+$+Cow-y=';<@CoCoCo5$5$w-BOBOe;e;U V+V+V+V+v&v&b@b@b@W*A#$O$+iXh&rXN,f+Q@~O+.9=m%m%m%P#d=t$KoKoKo0,d=0,2#2#vXvXvXvXu*@>6@6@6@l.l..:7+*&.:*&*&r 7+r +Xm%m%l;iXl$M..;t+a .;(&M$n#';t$o=m%m%m%_:7>u@`O]>9%{X4*(.9<:#7*7*s.s.s.';+&>++&>+6 6 6 6 )$#oV@T,>+,,y%0:N,A*t>L.c+1;V a&a&0:0:0:L.h@h@t>A*t>t>c#c#)XK=K=K=[o[oN,N,[o,.. +;}OCoG@m%v:+XP#`-l.@>d=t$p;F&C>T,/-';{:kXQ$go}OF-,-z,A:+;+;A:WX2O]$4- ", +" v%I-n=M$-%+;Q@z,#<% 0:)XK=n#w-)$6 )$G#{.D+p;KovX.:`-4OL>I+' P&o=e<{XM$F.kOS,s>P*E.z@E.r:r:r:r:r:r:L-Q;mOU :#:#>++&kX,,,,,,,,Co5$5$5$9A#H,$+>${Xgo,.q>},A%Q@d%m%m%m%4Ot$u-0,d=0,d=2#2#vXvXvX@>@>@>6@u*6@l.l..:.:*&.:7+7+r 7+`-`-4OP&m%m%+X+,r#5&t+t+u@1;5$D+ -m%m%m%m%m%m%Q;=XC.M-<=9%z@);p:5$kX7*7*s.';s.+&+&+&+&+&6 6 /-;O)$/-C>b@+$c#0:h@t>c+kO9%V 1;V a&a&a&0:0:0:A*h@t>)XA*t>c#)Xc#K=c#c#N,[o[o[o[o}O>:y+WX, `-m%I+G@ -|$7+@>0,u-z%F&#oT,)$>+7*:#9P&l;I+;oG#kOqo]>~:n#s>z@E.z@P*E.M+r:S,5=s>p:w-:#>+)$<@:#{::#y=:#,,,,,,Co5$9@>6@6@u*l.l.l..:.:*&7+7+.:r r `-`-|$|$P#' m%m%*&#t>)Xc#c#K=c#K=[o[oZ$[oZ$io+;,XM+t$' m%G@;o4O*&u*d=KoZO{.(*G#;O>+7*kXkXL-<=,.Y:s@H%&-y+^>_o/:L$Y% ", +" v%o*iO!+y+j *.s@<=K=h@6X)X$O;O>+)$_=(*F&p;u-d=vX6@`- -o=' m%I+`-,,% &-}OX+n#s>P*z@r:r: OrX O);BO5$/-;O/-s.7*<@7*{:kX,,y=y=,,,,y=5$5$w-9vX@>@>6@6@6@.:l..:*&.:.:7+*&r r r 7+`-`-4O4O4O4OG@m%m%l;V@.# O#ou*m%m%m%m%m%m%m%m%m%l;m%9%,L.1;1;t>0:3-go=t>)Xc#)X)Xc#K=c#N,Z$[o[o[o%*==_#;*#ov:m%P&;o),*&6@vXt$ZOD+(*G#;O6 s.{:{:; ,-L;L;r&M-_#7&qoM-O#7=Y% ", +" P%c=Y-A:j tO`OF.Y:t>h@]>[oA#G#>+)$_=(*F&p;ZOd=u**&),P#+Xm%' v:6@A#]@!+)X O{Xz@r:n#rXrX%,e;BO<@;O;O6 +&';';s.s.7*kX{::#:#kXy=,,,,Cow-w-BOBOBOd%e;e;U U U p:p:p:b@W*!=$+iXh&;*N,f+A:M;b-);m%m%m%L>vX2#@>vX@>@>@>6@6@6@.:l..:.:*&*&7+7+r r |$`-|$`-4O|$),4O|$ -P&m%m%m%4O0,P#m%m%m%m%m%m%m%l;' l;m%m%m%M+TXs,,Xb A*L-co!=9<,,kX{:{:7*<@<@7*/-W D+!=.#1;=c#c#)Xc#K=N,[oK=N,N,L;H%tO)XkXL>m%v:;o -r l.vXt$ey+&-. A.O b: ", +" %ox@l:,Xj &-. >:`+L.A*}#% A##o+&;O#o{.D+z%e<2#6@*&4OL>+Xl;' v:d=9=hOM$c+Y={X.#;*E.T-p:{:C>G#;O6 6 6 +&';+&s.<@s.7*{::#y=:#:#y=,,,,Cow-9A#, %,n#+$U%N*&-+.A:5$m%m%m%),2#2#@>u*@>u*u*l.l.l.*&*&*&7+7+7+r r |$|$4O4O|$4O),), -),),L>m%m%m%m%m%m%m%m%m%m%m%l;' I+P&I+m%m%m%m%=)X)X)Xc#c#c#K=N,[oK=% a#+;}#U o=m%P&o=P#`-l.@>0,u-W V@(*T,/-s.<@{:z@%*% N,3%z,==j tOH%s@%*k&Y P% ", +" s;W>a#^>j _#M$r&,.L.)X]>)XW*#o>+;O#oj:p;e<0,vXl.7+4Oo=v:m%' v:e++&';<@<@7*kXkXkX:#y=,,,,y=Co5$w-BO9Z$[ohOa#,X+;-%!+q>z,-;U%0:t>,.goU _=6 ;OG#j:p;ZOKovX.:r 4Oo=I+l;v:G@F&.#}&r&L-@@ooT,V@(*C>#oT,T,T,)$/-6 /-6 >++&+&s.<@7*{:{:{::#y=y=:#y=Co5$9P&m%m%G@*&u*@>l.l..:*&*&*&7+7+r r `-`-`-`-|$|$),), - -),),P#P#;o;oo=v:m%m%m%m%m%m%' I+I+P&P&P&P&I+l;m%m%m%m%V+`OA%},F.[o @mO, (.5$';#oG#ooH$L-kO% )X.#;*rX5=.#+,gogogogo+$3-=<3-=<=)X)Xc#K=c#K=N,[oZ$[oioy+==8-u*l;m%+XP#4O7+6@d=u-p;F&(*T,/->+7*{:!=5=L;F-ioq>*.-%j ,Xa##I+l;P&;oG#A*}&h@x>C>{.(*C>#o#oG#;O;OT,)$;O/-)$6 >+';';';<@<@{:kX{::#y=y=y=,,,,Co9<5$9Q$4*h&rX[or&A:M;7>(.m%m%m%;ou*l..:.:.:l..:*&7+7+*&r r |$`-|$|$|$4O -), -P#P#;oL>;o;oL>o=' m%m%l;' l;' P&P&P&P&P&' ' l;m%m%l;m%m% OTXs,,X-;A*L-9=!=:#T,U 3A*)Xt>)XK=K=K=N,[o[oK=Y:&-tOY=e_=T,>+7*kX9< OY:U%6XN**.tOy+Q@a#f+9-D,P% ", +" 8#Jo}X*.+;+;A:a#io[oL.U%t>$#{:>+)$#o(*j:W u-0,vXl.|$P#G@P&I+I+),kXL;A=3<>+(*C>G#C>#oG#_=T,T,T,;O;O)$/-6 >++&+&';<@s.<@{:{::#:#:#y=,,Co5$5$w-9<9=<,.WXtOE+`O6 m%m%m%),u*.:l.l.*&*&7+7+*&7+r |$`-`-|$4O|$),), -P# -;oL>L>L>L>L>G@+Xm%l;I+I+P&P&P&P&P&' I+l;m%m%m%m%m%l;m%m%N,(&b*H%]>1;M+Q$v&iXco; % ]@V ; @;* @rX.#rX.#rX5=5=+,+,go+$+$3-=<=<=A*t>)Xc#c#K=K=c#K=[o[o[oL;Q@-%rX(*+Xl;+X;o),*&u*2#KoZOj:V@G#T,>+7*kXkXn#]>U%Y:F.A;tO7&^>A=r&U.c@^% ", +" 8#+#}o!+j +;!+q><=K=h@]@h@oo6 ';)$_=(*F&p;u-d=u*.:`-P#+X' ' v:*&x>Y:#G#_=G#_=;OT,T,;O)$6 /->+';';>+';<@7*{:{::#,,y=y=,,,,Co5$5$w-9L>L>L>o=o=+X+X' P&v:v:P&P&I+' ' l;' m%m%m%m%l;m%m%m%2#3%E+j A=% rXH$P*y%N,#<0:; ~% @0.0.;*;*~:~:rX.#.#.#5=+,go+,+$gogo+$=<3-=t>A*t>)Xc#c#N,N,N,[oK=U%*.-%c++&G@m%P&o=4Or l.vXKoz%D+{.#oT,+&7*kX{:s>#:*,Y#h ", +" 8#+#I=!+j +;*.s@]@c#A*]@a&v&T,+&/-_=V@D+z%e<2#u*.:`-P#v:m%I++XvX4*`+[o$O_=#o(*#oC>G##oG#_=T,T,_=;O/-6 6 6 +&+&>++&s.<@{:{:kX:#y=y=,,,,,,5$5$w-9<9;oo=o=o=o=+X+Xv:v:v:P&I+' I+I+I+I+' ' l;m%' ' m%m%m%m%m%A#A:l$==s@L;1;U%>:%*5=; X+X+Q;0. @;* @~:~:~:rXrX.#5=.#5=go+,go+$+$3-=<=<=A*t>)Xc#c#c#c#c#[oZ$N,}Oz,_#F-9<;om%I+o=),`-.:vXKoz%W j:G#T,>+<@{:7*P*,-L;}O-;_o_#&:qoM->:J@m&1$ ", +" 8#+#V,}&&:-%H%s@<=)XA*]>L.v&T,>+)$_=(*D+p;u-d=u*7+|$P#v:m%' +Xt$M+]@a&b@_=#oC>C>#o(*#oG##oG#G#T,;O;O)$/-6 6 +&+&';<@s.7*kXkXkX:#y=,,,,,,5$w-Co97+7+7+7+`-|$|$4O4O4O),), -P# -P#;o;oL>;oL>G@o=+XG@G@G@+X+Xv:v:v:' I+I+' l;l;m%m%l;l;m%m%m%m%m%m%m%m%0.b*TX*._o,XA=t>go0.0.Q;Q;Q;Q;0. @ @;*;*~:;*.#.#rX.#.#rX+,go+,go+$+$go3-3-kOkOkO9%1;1;1;V V c+a&a&a&L.0:0:L.A*A*A*A*t>)Xc#)Xc#K=c#N,[o)Xa&h@hO]>ooP#m%P&G@4Or .:u*0,ZOW {.G#;O/-';{::#z@io,.F-3%M-_#7&_#M-r&]@!*`> ", +" ^%F,:.,X7&-%H%>:6XA*A*]>t>v&T,>+;O_=C>F&z%e<0,6@`-),;o+Xl;' v:e< O,-3-U #oC>(*#oC>C>C>#oG#T,)$T,T,;O;O6 6 6 +&';+&';<@7*{:{:kX:#kX:#,,,,5$5$5$5$w-BOd%V+V+p:(.(.H,[%%,kOz,A;A;j C:M-{.m%m%m%;o*&`-|$|$4O4O4O),),),P#P# -;o;oL>o=;oL>o=o=G@+XG@v:v:v:P&P&P&P&' l;l;l;l;m%m%m%l;l;m%m%m%m%m%m%l;I+v:}OM;lK=1;.#0.0.Q;X+~%~%Q;Q; @ @;*;*;*~:rX~:rX.#.#.#+,+,+,+$3-+$3-=<=t>c#c#)XK=Z$t>goH,#oA#U%F.$+4Om%I+P#),4O.:@>Koe:]@w%(% ", +" .&AoK:,X7&tO. r&`+h@t>ioA*p:T,>+;OG#(*F&ZOt$0,u*r -o=v:m%' +XW @3%5=BOC>C>(*{.(*(*(*C>G#_=;OT,/-/-;O;O6 6 +&';+&';<@<@<@7*kXy=y=:#y=,,y=,,9<9$t>}#}OU%N*A:7>A%c#u*m%m%' -r |$`-4O),),),), - -P#P#;oL>L>L>G@o=o=v:G@v:v:+XP&P&P&I+I+' l;l;m%m%m%m%m%m%m%m%m%m%m%m%l;P&G@9<)X&-M;l<7&}&s@Y:h@=<.#Q;Q;Q;~%X+Q;Q; @;* @ @;*;*;*~:rXrXrX5=.#+,+,go+$+$+$=<3-=t>)X[o% 0:>$';#oV@C>b@% M$4*),m%I+G@;o`-.:@>t$u-W j:#o;O/-';<@:#r:Y:L;[o#7&},H%>:Y:L:E- ", +" K@`*Uo==j &-. r&`+h@t>ioA*v&G#>+;O#oV@D+ZOKo2#6@7+),G@v:l;l;+Xp;+,b ;*BOC>V@C>{.(*(*(*C>G##o_=;OT,;O)$;O6 6 6 >++&s.<@s.7*{:7*7*kXy=,,,,Cow-BOBOBOe;U v&v&b@rX% 1;goL.Z$<=z,_#~Op#3L>o=o=o=G@G@o=v:+XP&I+P&I+I+I+I+l;l;m%l;m%m%m%m%m%m%m%m%m%m%v:;o;O+,*.TX~O+.^oj Q@A=ioF-c++,;*X+X+~%~%X+~%~%Q; @;* @~:;*;*~:~:rXrX.#.#+,+,go+,go+$+$3-=<=V@u-ZOF&T,b@Z$M-co7+m%l;+XP#`-.:vXd=u-W {.(*_=/-<@{:{:8-}O}OF-hOa#Q@j },H%F.6XTom> ", +" } [-q>==j &-M-f+U%0:t>]>t>v&_=+&)$#oV@F&ZOKo2#u*r P#o=P&m%I+o=F&9%>:~%9<#oV@C>j:V@(*C>C>G#G#G#T,T,T,;O;O/-6 /-+&';';s.s.s.7*{:kX:#,,,,Cow-5$9<9]@WX,X7&#=+;>+m%m%l;o=),),), - - -;o;o;oL>L>;oo=o=+XG@G@v:v:+XP&P&P&I+I+l;' l;' m%m%m%m%l;m%m%m%m%m%m%v:;oW P*-;+;~O#=C:l$C.tO!+A=-;,.A*kO~:0.~%; ~%~%X+~%Q;Q;0. @ @;*~:;*~:rXrXrX.#.#5=+,go+,go+$+$3-=<3-kO=<=<9%1;1;1;V V a&a&a&0:0:L.L.t>[oU%9%$#9<>+ed=u-W {.(*_=/-s.{:{:%,Z$% [o#j:{.V@(*(*C>G#G#_=T,T,;O)$)$/-6 6 >++&s.<@<@<@{:{:kX,,,,,,Co9L>o=o=L>o=+X+Xv:v:v:P&P&' ' P&l;l;m%m%m%m%m%m%m%m%l;m%m%m%P&L>ej &-,X. s@#<,.A*9%5= @~%X+; ; ; ~%~%Q;Q;Q; @ @ @;*;*~:~:rXrX5=.#5=5=+,gogogo+$3-3-=H$ood%C>d=d=z%W p;z%D+V@/-U 0:. P*0,' l;+X;o|$*&u*2#eZ$K=,-z,Q@j -%!+s@%*'XR ", +" V*]&WXqoy+_#M--;}Oa&A*<=V d%_=>+;OC>F&D+z%KovX6@7+4Oo=I+l;P&o=V@K=WX{X:#G#(*V@j:{.V@(*(*C>G#G#G#T,T,T,T,;O/-6 /-6 +&+&s.<@7*{:7*{::#,,,,y=(.P*~:rXA*N,=<5=1;Z$Y:#L>o=o=o=+XG@v:v:v:v:P&P&' I+I+m%m%m%m%m%m%' m%m%m%m%I+o=2#!=3-s@TX0O#%E+TXy+&-,XA;_o>:#kO.#;*0.X+; X+L-; ~%X+~%Q;X+ @ @ @;*;*~:~:.#.#rXrX.#5=+,5=+,+$+$go3-=$!=kX@>d=W F&F&D+p;p;D+D+V@s.U 1;M- Oe`-.:6@2#e+;OC>j:D+ZOKo@>l.r -L>I+I+v:o=(*Z$a#P*:#G#(*j:F&{.V@V@C>C>G#G#G#;O;O_=T,;O/-6 6 >++&+&s.<@<@7*7*kXy=kX4*Y=S,9%L;A*.#kON,,.}#b a#H%==+;b*b-=X.;p#[%' m%m%P&L> - -P#L>L>L>L>o=o=G@G@+X+Xv:v:P&P&P&I+I+I+m%m%m%m%m%m%l;' ' m%m%m%),CoY=Y:u@t+@:#=^oy+},==!+_os@b <=`+F-A*1;3-5=Q;X+~%X+X+H$; ; ~%~%~%Q;~%0. @ @ @;*;*~:rXrXrXrX5=+,go+,+,go+$+$=<=<=V@{.F&D+D+p;z%F&F&C>7*V+3-M-~%p;v:' v:P#`-7+u*d=u-W D+(*T,;O';7*{:T-3-F-N,ioq>,Xj -%!+N*Y::=T= ", +" K E;WXqoj _#M$3%U%a&A*`+goBO;O>+;O#oj:W ZOKo@>l.*&),o=P&I++X;o_=}Oq>r::##o(*{.F&{.j:j:C>(*#oG#G#T,T,T,;O;O;O/-6 >+';+&s.<@<@';s.v&%,8-~:F-t>.#.#h@L;]@b N*M-!+&-y+TX~OC:A%^>b Q;@>m%m%l;+XP#P#L>L>o=o=G@G@G@G@v:+Xv:P&P&P&I+I+' ' l;' m%m%m%l;' l;' ' l;m%m%o=[%^>JXr#~#b-C.-%^>}&. WXf+]>%*F-)Xa&9%+$rX0.Q;; L-X+; ; H$H$X+X+~%Q;0.Q;Q; @ @ @;*;*~:.#.#rX.#5=.#+,gogogo+$+$=<=<=_=)$';7*7*!=5=U%N,ioa#,Xj -%!+WX]>d;Y. ", +" 2$_;a#_#j &-M$3%% a&t>U%~:w-)$+&;O#oj:W z%Ko@>l.7+4Oo=P&' +XP#>+,.s@mO{:G##o{.W F&V@(*(*V@(*#oG#_=;OT,/-)$;O6 6 6 +&';+&;O7*!=u.H c+K=X+n#rXh@,.,-F._o}&^>-%C.^oC:+.y+q>0:A#),m%m%m%m%l;G@;oo=L>o=o=o=o=+Xv:+Xv:P&P&I+' I+l;l;' m%m%m%l;' ' ' ' I+I+I+' m%m%z%a#g*[,b-u@tO,XH%A=>:hO]@% t>a&9%3-.#;*0.~%; H$ OH$; L-L-L-; ; X+~%~%X+Q;Q; @ @ @;*;*;*rXrXrX.#.#.#5=+,+,+,go+$+$=<3-=<3-1;h@t>= @`+F-ioa#,Xj tO*.q>,-p=MO ", +" /;,@A=_#j _#M$3%}Oa&)XZ$Q;9<)$>+;O#oj:D+ZOKo@>l.7+4OL>P&l;+X),';`+s@8-7*G#C>j:F&j:V@{.V@(*(*G#_=G#T,T,;O)$;O/-6 /-T,>+BOU [%+,L.S,8-h&~%kOc#Y:r&M-,X},&:N=M;C:7>}&%*3[,lq>,Xj -%}&q>,-+ 9X ", +" #.,@z,_#+;_#M$3%U%L.t>F-0.w-;O>+;O#oj:W ZOt$@>l.r ),L>P&' +X -+&,.s@3<<@#oV@{.D+{.{.{.V@(*V@(*#oG#;OT,T,;OT,(*(*{:d%(.P*L.~:8-9=mOh&L-+,t>Y:>:A;},b*M;=Xb--%F.~%#om%m%m%m%m%m%m%m%l;' v:G@+Xv:+Xv:v:P&I+P&I+' ' l;l;l;m%m%' ' l;l;' I+I+I+' P&v:v:P&' m%m%l;Co#=~#p#tO`OF.<=}O)Xc+=<+,;*Q;~%; L-H$Y= OY=Y=S,H$S,S,L-; L-; ; ; X+~%~%~%~%Q;0. @;*;*;*;*rX.#rX5=5=.#.#+,+,.#gokO0:c+9%1;n#w-C>T,6 6 ;O)$T,T,T,_=#o#o#o(*(*(*{.{.F&D+j:j:V@;Oy=U Q;r&rX#o+X' v:P#`-7+l.2#u-W F&(*_=/-s.7*{:W*~%,.U%]>WX,Xj tO*.N*}#z-n: ", +" @X_;a#qoj &-M-hO}O0:t>,..#9<)$>+;O#oj:D+ZOKo@>l.r ),L>P&' +XP#6 L;N*6;{:C>j:{.D+F&j:{.{.(*(*C>#oG#T,T,{.j:/-kXy=9==<~:M+>$>$3~%1;U%b `O-%^oA%&:M$9%U P#m%m%m%m%m%m%m%l;' I+v:G@o=v:P&P&v:P&I+' I+' l;m%l;m%m%m%l;l;l;l;' ' I+' P&P&v:P&v:+XP&l;m%m% -~%T@(&y+!+F.6XK=c++$;*Q;; H$S,Y={Xn#n#Y={XY=n#Y=S,S, O OH$L-L-L-L-; X+~%~%~%Q;Q;0. @ @ @;*;*rX.#rX.#5=rX~:goc+0:9%0:9%, +&+&>+6 6 6 6 )$;O;OT,T,T,_=G##o(*(*C>V@j:D+D+j:F&{.;O,,V+0.f+;*C>+X' +XP#`-*&u*d=t$W D+(*_=/-s.<@7*A#;*L;% ioWX,Xj tO*.N*<=R:9o ", +" Y#E;WX_#j _#M$b U%a&t>Y:3-BO)$+&;OC>j:W eI+' v:L>G#% N*r:{:(*F&F&p;D+F&{.j:V@#o#o(*(*D+(*>+7*!=X++$n#6;M+8-%,>$8-y%r:Y=~:A*]@z,^>b-u@F-$O2#;om%m%m%m%m%m%m%l;' v:G@+X+XG@v:v:v:I+P&I+' l;' m%l;m%l;l;' l;' ' I+' I+I+P&v:P&v:+Xv:v:G@I+m%m%m%u->:(&l$&-_oioK=9%~:~%H$S,Y={Xs>s>s>P*n#n#{Xn#n#Y=Y= OH$S,L-H$; L-; ; ; ~%~%~%Q;Q;0. @ @ @;*;*~:.#~:;*rX+$1;9%0:A*mOU ,,<@6 >++&+&+&/-/-6 ;O;OT,;O;OT,G#G#C>(*(*V@{.j:D+F&j:V@;O:#V+~:s@Q;{.v:' +X -|$*&u*d=u-W F&(*G#/-';7*7*$Ogo% N,ioWX,Xj -%!+s@Y:h%0& ", +" E-G%WXqoy+&-M-b }O0:A*<=1;e;;O+&;O#o{.D+ZOKovX6@7+),o=P&l;v:o=(*K=q>z@7*C>V@D+W D+F&j:{.(*(*W F&T,)${:r:rX O{Xs>6;>$>$3<3<8-8-y%E.H$+$N,3%*.y+~#`+t$m%m%m%m%m%m%m%l;' P&+XG@G@+XG@+Xv:' I+P&' ' l;l;l;m%m%m%l;' ' I+' I+I+' ' P&v:P&v:v:v:+X+X+XG@' m%l;m%T,l$(&u@,X>:U%c+~:H$n#s>z@s>P*E.z@s>z@s>{X{Xn#n#n#Y=S,S, OL-H$L-; L-; X+~%~%X+Q;Q;0.;*;*;*;*;* @ @+,1;kOc+K=rXx>e;,,+&>+';7*<@';+&+&6 6 /-)$;O;O)$T,_=G##o#oC>(*(*V@j:D+F&j:V@T,{:d%+,A=X+W ' ' v:;o`-.:u*2#u-W F&(*_=)$s.7*7*[%9%F-K=}#a#==+;tO!+N*Y:Z@NX ", +" (%LOq>==j &-M-b ,.h@A*]>0:v&;O>+;O#oV@F&e<0,vX6@7+),o=P&m%P&o=V@t>q>Y=kXV@{.D+F&D+D+F&W ZOj:;O';, O On# Os>mO8-3:,XN=~On#l;m%m%m%l;l;I+I++X+Xo=G@o=+X+Xv:P&I+' ' I+' m%m%m%m%m%m%l;l;l;' I+' P&P&I+I+P&v:v:v:+X+X+X+Xo=o=I+m%l;' b@0OE++;`O,-K=+$~%{Xz@E.r:E.z@E.z@P*z@P*n#{X{Xn#n#Y=n#S, OH$L-L-; L-; ; ~%Q;~%Q;Q;Q; @;*Q;Q;rXgogo1;}O1;coA#p:+&/-<@kXkX7*s.<@';';+&+&6 6 )$;O;O)$T,T,T,G##o(*(*(*V@j:j:D+j:V@G#<@V+1;M-n#t$l;l;+X;o`-.:vXd=u-W j:C>_=/-s.{:{:4*0:F-N,}#a#==j },*.N*Y:(-0X ", +" *@,@N*,Xy+},`Or&`+h@t>}#A*v&T,>+;O#oV@D+ZOKo2#u*7+4OL>P&m%' G@j:L.q>L-:#{.F&D+D+z%e==E+Q@p:I+m%m%l;I++Xo=o=o=G@G@+X+Xv:v:v:P&' ' I+I+l;m%m%m%l;l;l;' l;' ' I+I+P&+X+X+XP&v:G@+X+Xo=G@G@o=+XI+m%m%r 5=5ob-_#a#6Xh@rX OP*r:r:E.E.E.z@z@P*P*z@{X{X{Xn#Y=n#n# OS, OH$ OH$L-X+; X+Q;~%Q;~%~%~%0.rX.#+$t>N,S,@@$O,,;O+&,,,,,,:#{:7*<@<@<@s.';';6 6 /-)$)$)$;OT,T,G#G#C>(*(*{.{.V@F&j:V@C>+&(.h@. h&@>m%I++XP#`-*&u*d=u-W V@(*_=)$<@{:{:9=c#F-F-#)X}#)XV+_=+&;OG#(*D+eG@+X+Xv:v:v:I+I+I+I+' m%l;l;m%m%m%l;I+' ' ' ' P&I+P&v:v:v:v:+X+X+XG@o=G@o=L>L>L>v:l;m%m%F&M$E+p#Q@>:}O1;~%{Xz@h&H h&h&E.z@E.z@P*P*P*{X{Xn#{Xn#Y= O OS,H$ OH$L-; ; ; ~%X+X+~%0.0.~:A*}OrXy%>$(./->+y=CoCoCoy=y=:#{:{:7*<@<@<@';+&+&6 /-/-;O)$T,;OT,G#G#G##o(*V@{.j:D+D+{.C>/-b@K=. mO*&m%I+G@;o`-*&@>Kou-p;V@#o_=/-s.{:kX37&},H%F.6X@ %% ", +" q@&#C ,X7&-%H%>:%*t>)Xiot>p:T,+&;OG#(*F&ZOe<0,6@r -o=+Xm%l;+Xp;go>:Q;:#F&z%z%0,(.iXy%H$5=L-3<8-6;H M+H 6;6;6;6;6;mO3<3o=L>L>P#+Xm%m%m%+&(&A%&:*.3%N,goL-P*r:h&H M+h&r:z@E.z@P*s>z@P*{X{X{Xn#n#S, OS, OH$L-L-L-; L-~%X+X+~%=C>(*j:j:j:D+V@#o;Ox>F-M$9=|$m%P&L>P#`-*&vXKoe:Y:q=%: ", +" ^%~Xk;,X7&tOA;s@6XA*A*]>A*p:;O>+;O_=(*D+p;e<0,u*r ),P#+Xm%I++Xz%X+hOrX7*z%<@Q$[%{X~:~%h&y%h&h&h&M+H H H 6;6;6;6;6;y%3o=L>;oL>;o;oP&m%m%I+$+@:b--%. ]>A*.#H$P*r:r:M+h&h&h&r:E.E.z@z@P*P*{X{X{Xn#n#n# O OS, OL-L-; ; OS,~:Z$c#~%S,H d%>+Coe;e;9(*{.j:j:j:(*C>T,!=U%a#@@4Om%P&L> -`-*&@>Koz%W j:#o;O/-s.7*7*M+]@`+F-b M$^>y+_#. f+Y:J&LX ", +" 8#}%}o}&y+-%A;N*<=)XA*ioL.V+T,+&/-G#(*D+z%u-d=u**&r P#v:m%I+v:eY:1;%,, mOQ;rXs>h&h&h&r:E.r:h&H H H H H H 6;6;6;6;mOmO6;H h&{X0.0:]@A=_#(&Q@v&I+m%m%I+v:v:I+I+' l;l;m%m%m%m%m%m%l;' I+I+' P&I+P&P&v:v:P&v:+X+Xv:G@G@o=G@L>L>L>o=L>;oL>P#L> -L>' m%m%u*kO[,s,_#a#`+c+ @Y=E.r:h&H M+h&r:r:z@E.z@z@P*s>s>{Xs>{Xn#n#S, OS,H$; Y=s>; c+N,+$~% OT-y=,,e;v&U e;BO9(*(*{.j:{.(*V@T,T-L;F.Q$ -m%I+o=),r l.vXt$z%W {.#o;O6 ';{:kXr:]>`+U%b M$qo7&_#M$b 6XqOn% ", +" 8#+#I=*.j j !+N*<=N,A*]>0:U )$s./-G#{.D+p;e}#M-tO#%]>eo=L>;oL>;oL>;oP#P#P#),+Xm%m%m%_=z,C:b*A:r&% kOX+s>r:M+H H H h&r:E.E.z@z@P*s>P*s>n#{Xs>n#n#n#H$n#z@P*3-[o1; @5=y%9<9m%I+G@ -r 6@2#KoZOF&j:G#T,>+<@7*{:s>,-,.U%f+`O_#y+qo_of+6Xt#C% ", +" 8#<*I=*.-%+;A:q>ioZ$A*]@L.b@>+s.)$G#V@j:W eP&I+I+l.oo#m%m%l;' l;m%l;m%m%l;m%m%m%m%m%m%' ' I+P&P&P&P&v:v:+X+X+X+XG@o=G@G@o=o=L>;o;oL>;o;oP#;o - -),),P&m%m%m%Co(&lz@P*n#n#n#Y=n#h&r:X+a&1;+$kOL-!=v&p:(.(.p:p:v&V+V+U U e;BOBO9+6 6 6 /-;O)$;O_=_=#o#o#o(*C>(*(*(*V@j:>+H ]@Z$9+{:kX{:s>hO,.,.r&H%&-+;==z,b N;>=K@ ", +" 8#Jo@+H%-%j Q@A=,-F-L.%*A*$+s.+&)$T,#o{.W eI+' I+4O5$6XqoK= Os>P*P*P*z@E.E.r:h&h&h&h&M+M+H H H H 6;6;6;H 6;mOH P*L-go[ob !+b*+.co+Xm%m%m%m%m%m%m%m%m%m%m%m%P&m%m%l;P&P&P&+X+XP&+X+Xv:+XG@G@G@o=o=L>o=L>;oL>P# -P#P#P# - -),),), -P&m%m%P&$#,>s,},z,<=L.rXS,E.h&M+H H H H M+r:h&E.z@z@P*P*P*{Xs>r:H s>=+6 6 )$;OT,T,T,_=G#G##oC>(*(*V@(*j:;OP*io=<';G@' G@P#4O7+u*d=u-z%j:(*G#T,>+{::#:#z@,-Y:6Xs@A;tOj Q@a#f+[&l+@& ", +" 8#;$(XM--%y+^>z,#+)$G#j:W ZO0,vX.:|$),o=I+' P&P#6 Z$_#L;~%s>z@z@z@z@z@z@E.M+M+h&h&M+H H M+H H H 6;6;H y%mOH P*; 3-Z$r&A:b-*.w-I+m%m%m%m%m%m%m%m%m%l.e;s.' m%m%m%I+v:P&+Xv:+X+Xv:+X+X+Xo=L>o=G@L>;oL>P#P#;o - - -), -),4O),4O -' m%m%2#L.a TX^>q>,.1;0.{XM+H H y%y%H H M+h&r:z@z@z@P*P*r:6;E.Q;+$.#V c#r:$+$Ooov&W*W*x>x>b@b@b@(.p:V+U U U e;e;BOBOBOw-w-5$,,,,,,y=y=:#{:{:{:<@<@+&+&';>+6 6 /-;OT,;OT,;O_=G##oC>#o#oj:ZOd=s.V WX0.V@v:m%+X),|$7+6@d=u-W j:(*T,)$>+<@kXCo{X<=%*]>N*!+-%j A:a#f+]=O=P% ", +" $ q:~*a#},j _#_o-;L;L.t>Z$~%BO;O';)$G#{.D+ZOKovX6@7+4Oo=I+l;P&o=j:a&^>io~:n#s>P*z@z@z@E.r:M+M+r:h&h&H H H H H H 6;6;H 6;mOH P*; =<[of+*.=Xc#Kol;m%m%m%m%m%m%;o(*x>A*u@c#m%m%m%m%I++X+Xv:v:G@G@v:+Xo=o=L>L>L>o=L>;oP#;o - -P# -P#),4O),|$|$`-L>m%m%l;';A;=XC.!+f+Z$+$L-P*h&6;y%y%6;H H H h&r:r:z@z@H mOY=;*;*=x>b@b@b@p:v&v&U U U e;e;e;BO9<9D+ZO{.6 :#E.. ==z@Kol;l;G@P#`-*&6@2#e3%a=@#P% ", +" Won-q>qoy+&-. f+L;h@A*%*V (._=+&T,G#(*F&z%t$d=6@*&4OL>v:l;' P&e<~:!+f+5=Y=P*P*z@E.z@E.r:h&h&r:r:h&H M+M+H H H 6;6;6;M+H 6;z@L-3-[o3%H%=Xy%o=m%m%m%m%G@d=7*~%M-~Ow@~# @m%m%m%' v:+XG@+Xv:o=o=G@G@L>L>L>;oP#P#;oP# -;oP#), - - -),|$|$4O`-`-+Xm%m%I+A#=XlrXS,E.M+y%y%y%6;H H H h&E.6;H z@H$Y=5=}Oc+3H,$O$O!=!=A#oooox>ooW*b@p:p:p:V+U U e;e;e;BOBO9<5$w-w-,,,,y=:#y=kX{:kX{:s.<@';+&';>+6 /-6 ;O;OT,;O_=C>F&D+C>6 A#S,V 3%&:A;_:`-m%I+o=;o`-l.@>2#u-W {.C>T,)$';kXkX$+9%% F-hO_oQ@j },A;s@eoVXSo$ ", +" c@,#z*Q@j tOH%>:Y:h@A*}#N,x>#o>+T,_=(*F&p;e<0,u*7+ -P#G@l;l;P&0,E.WXq>=s>E.z@E.E.z@E.h&h&r:h&r:H H H M+6;6;6;H H 6;H E.L-+,N,}#`OtOe;l;m%m%;oW h&#JX==BOm%m%m%I++XG@G@o=G@G@L>;oL>L>L>;o;o;oP#P# - - - -),4O4O4O4O4Or |$`-|$P&m%m%G@P*JXp#&-z,]@a&0.s>M+6;y%6;6;6;H H 6;6;M+E.s> Oc#% ; $#9=T-A#H,$+T-T-$OH,H,!=A#A#oooox>b@b@(.p:v&U U U U e;e;d%d%9<5$5$5$,,,,,,y=y=kX7*{::#<@<@<@';';>+6 6 /-;O;OT,C>(*#oC>7*mOkOt>F-`+a#7&>:x>;om%+X;o -`-l.vX0,ZOW V@G#T,)$';kX{:y%N,F-F-b M$^>y+&-`OF.`+| h.P% ", +" 6,zXD&A:y++;A;N*<=)Xh@}#N,x>G#+&/-T,(*D+p;u-2#@>.:`-L>v:' ' ' vX@@,-. a&S,n#s>z@P*z@r:r:E.r:h&r:M+h&M+H H M+M+6;6;6;6;H M+r:Y=~:h@Y:`OL;(*m%;ob@[o==l$O-5&.;[,0Ot+]>7+m%m%l;P&o=o=o=o=o=o=L>;oP#;o;o - -;oP#P# -),),4O4O|$|$4O`-|$`-r r ),' m%m%KoF-5&u@Q@q>L;kOX+z@y%mOmOy%6;6;6;6;6;3A#x>x>W*W*b@p:V+v&v&U V+V+e;e;BO9+6 6 ;O_=_={.T,@@~%c+Z$L;L;F-U%M$+;L;w-G@m%v:L>),7+6@@>t$z%p;V@#o;O>+s.{:{:{X]@U%}O>:M$_#&:_#. f+-.U=8# ", +" ^%pO>&!+j j }&WX]>N,A*<=K=!=;Os./-_=C>j:p;u-d=vXl.`-;oG@I+l;I+*&p:6X^>)XL-n#s>z@z@z@E.E.z@E.h&r:r:h&M+M+H H H H 6;6;6;M+M+M+s>Q;9%F-_oy%s.P*}#_#l<#=T@#=#=T@#=O-t+9%m%m%m%' G@L>;oL>L>L>;oP#;oP# -P#P#P#), - -),4O|$|$|$|$|$|$`-r r r *&L>l;m%I+,,}&#=&:!+b [o+$L-E.6;y%y%mO6;y%9=8-rX% h@s>r:8-u., [%);[%[%$+$+$+, Q$Q$$OH,H,A#ooA#oox>oob@b@b@(.p:V+U V+U e;e;BOBOBO9<5$5$Co,,,,y=y=kXkXkX{:s.<@';+&';>+>+)$C>j:Cos>+,A*% L;}O[oZ$Z$`+!+tO1;>+v:m%+X;o -7+@>2#Koz%D+C>G#)$>+7*{:{:; #<,.,.s@H%_#7&qo_o/:x v@P% ", +" v N 1-A;-%+;Q@A=hOZ$h@Y:)X$+>+s.6 ;OG#j:W el.r ),L>I+l;I+),<@c#_#Y:0.n#s>P*z@z@z@z@E.z@r:r:h&h&r:H H H H H 6;6;H H H M+z@H$+,A*]@N,U%M$j b*^o~Ob-N=l$~OC:O-A%6;m%m%m%I+;o;oL>;oP#P#;oP#P# - -), - -),4O4O|$4O|$`-`-r r r r r 7+7+7+v:m%m%v:iX(&A%+;. }#)X.#Y=h&6;6;y%9=@@n#[ot>~%Y=P*_:u.4*_:_:@@@@);););, [%[%, $+, Q$$O$OH,!=A#ooA#x>W*b@(.(.p:v&V+U e;U U e;d%d%w-w-5$CoCo,,y=:#y={:{:s.<@<@';';_=p;7*H ; 3-c#% Z$Z$Z$Z$F-F-F-]@},&-L-F&v:m%G@ -`-r @>d=t$W j:C>T,)$>+7*:#7* O}#`+6Xq>*.},j ==A=/:h,soP% ", +" v%C*]+M-},j ==_ob U%h@Z$c#mOkX>+>+;OG#{.F&z%KovXu**&),L>v:l;m%+X{.~:A:b .# Os>s>P*E.z@E.E.z@z@r:h&M+h&M+H H H H 6;6;6;H M+h&r:{XQ;+$h@L;,-H%j +;Q@,X^>&-7&N=+.O-A:d%m%m%l;v:;o;o;oP#;o;o -P# -),),),4O|$4O4O4O|$`-`-r r `-r 7+7+*&7+*&r ' m%m%G@0.w@p#_#A=Y:L.;*n#M+%,u.H 9%K=go~% Oy%iX4*iX$#_:_:4*@@4*@@););$+$+$+T-T-T-Q$$O$O$O!=!=!=!=!=A#x>W*W*b@p:v&V+U v&V+e;e;d%BO9$u*l;I+G@ -|$.:u*0,ZOW F&#oT,6 s.7*:#5$H$]>%*<=a#!+-%+;,XWX=@(;so ", +" 8#O@j.a#&-j _#. f+`+t>t>[oQ;d%;O+&;O#o(*F&p;e<0,u*7+|$P#o=l;I+v:Koy%>:z,1;S,{Xs>P*P*P*z@E.z@E.r:r:h&h&h&M+H H H H y%y%H M+H h&E.z@S,kO}#q>#<]>,-]>io>:M$Q@C.b-O-L;l.m%m%l;+X;o;oP#P# -P# -),),),4O4O4O4O|$|$`-`-r r r *&r 7+7+7+*&.:*&|$I+m%m%0,%*M.C.Q@N*,.c+; 3$%,$#9=iXiXiX4*_:@@u.u.u.[%);[%, $+T-Q$$OQ$!=Q$H,!=H,A#x>oox>W*b@p:p:p:v&V+V+V+U d%d%BO9Koz%W {.#oT,/-s.kX{:v&~:%*L;,-z,,X+;-%*.s@)-O:X@ ", +" P%g noN*qo+;tOA;F.Y:c#A*`+L.A#G#';;OG#C>j:D+e<0,u*.:r -+X' l;' *&x>%*,XK=L-Y=s>P*s>P*E.z@E.z@r:h&r:h&h&r:M+H H H 6;6;H H y%comO+,t>=<3-1;~:; rX=$>$8-%,co9=$#$#$#_:iXiX@@4*u.););[%, [%$+, T-Q$H,$O!=!=!=A#ooooW*b@W*W*b@(.p:v&V+e;e;d%5$';/-{:9=H 0.A*Z$c#t>t>)X)Xc#c#K=N,Z$Z$[oZ$Z$`+!+},h@s.v:m%+X;o4O7+l.2#KoZOW V@_=;O>+';:#kX4*V }OL;-;. ==y+_#`OF./$|XD: ", +" p>-@6&,Xj j !+WXioK=L.]>% $OG#<@)$G#C>{.W u-0,vX.:`- -G@v:m%l;4O<@h@-%6XQ;n#P*z@z@P*E.E.E.z@r:h&h&r:h&h&H H H H H mO>$3S,3$h&S,~:h@<=A=&-b-l$[%m%m%m%P&P#P# - - -),),4O),|$`-|$4O`-r |$`-7+7+r 7+.:*&*&*&*&*&*&6@6@G@m%m%+Xh&(&M;y+H%r&-;,.)X% N,Q;z@Y=n#n#{X{X{XP*P*P*E.h&E.E.h&r:h&H 6;y%6;6;mOmOmO3<3<>$co>$%,9=9=9=$#9=iX_:4*4*4*u.[%);[%$+[%$+, , Q$T-$O!=(.5$U iX6;z@a&F-t>A*t>A*A*A*t>t>)Xc#K=[o[o[o[o[o[o<=tO==H$F&' l;G@P#4O7+6@d=t$ZOF&(*_=;O';7*{:7*H$,.}OL;>:`Oqo&:_#. f+,.M@K. ", +" gON@fo*.+;y+,Xz,3%Z$L.]@F-$+)$';6 ;OG#(*W e OH {:>+,,9$O@@8-Y=9%`+q>},~Oz,';m%m%l;G@),P#),4O4O),),|$|$|$`-r `-`-r 7+r 7+7+.:7+.:.:.:.:*&6@6@l.l.I+m%m%;oh@g*b-b*qo. . s@Z$+$5=.#5=rX~:rX~:~:~: @0. @Q;Q;0.~%~%~%X+X+; L-L-L-H$ OH$ O OS,n#n#n#s>s>s>P*P*P*E.z@r:r:M+6;H 6;y%6;6;y%6;mOco$#4*3h@t>)Xc#K=N,[oZ$[o[o% -;7&M-iX6@m%P&o=),`-*&@>2#t$p;j:G#_=/-+&{::#7*rX#<`+%*N*A;tOy+^>A=,%#Xd !% ", +" .&i.i#. },j ^>_of+,.A*F-N,r:Co>+>+;O_=(*D+z%u-d=@>7+|$ -o=' l;I+d=>$s@M$L.; s>s>s>z@z@E.E.E.E.r:h&h&r:r:6;y%h&Y=n#n#X+z@v&#o;O+&<@kXkX5$d%v&!=_:z@+$`+WX-%+.h@l.m%m%I+;o),),4O4O|$4O4O`-`-|$`-r r r r 7+7+7+7+.:.:*&l.l.l.l.6@6@6@r l;m%m%vXN*,>~Ol$TX==>:]>`+[oK=K=)Xc#c#t>t>t>t>t>A*A*h@h@L.0:0:L.a&0:a&a&V V 1;9%1;9%9%9%kO=<=<3-+$3-+$go+$+$go+,5=rX.#.#rXrX~:rX;*Q;Q;rX+$+$[ob #h@0:h@0:L.h@h@t>t>t>)Xc#c#K=N,[oN,N,`+A=j ]>U P#m%P&;o),7+6@vXd=u-p;j:#o;O/-s.{:y=w-.#<=,.ioa#}&tO-%A:q>x%I.x-.& ", +" v%p%xOz,qo-%},`OF.6XA*0:F-1;!=T,+&;OT,#oF&z%u-0,@>*&r ),o=l;' P&*&b@% A:F-~%{XP*P*s>P*E.z@z@z@E.r:h&M+h&E.z@P*L- @, G##o;O)$6 ';+&7*kXkX,,BOx>_:z@kO6X_oj +.y%l;m%m%I+ -4O|$`-|$4O|$`-`-`-r `-`-7+7+7+7+*&.:*&.:.:l.l.6@6@6@6@6@u*P#l;m%P&W*y+@:(&l$7&^>H%a#F.f+b 3%hOhO#<}#,-}#,-,-}#io}#io<=ioioio<=]>]>]>6X]@]@6X]@6XY:Y:Y:%*`+`+`+`+,.,.`+,.L;,.L;U%}O% }OU%U%% }O,.U%b `OA;A=-;}#`+Z$c#h@L.L.0:L.A*A*A*A*t>c#)XK=N,[oN,N,F-]@}&qo3-6 +Xm%P&;o4O7+l.2#t$ZOp;j:_=)$6 <@y=kX);9%}O,.-;M$Q@j },A;F.&.&oN# ", +" P%3&c;F.==+;j !+q>ioK=L.6XL;);G#';/-;OC>j:D+eP*E.E.z@z@E.h&E.r:z@~%;*9=s.C>_=T,/-/-6 ';+&+&<@{:{:y=BOb@_:S,L.,-H%b*TXd%m%m%m%+Xr |$|$|$|$|$|$r r r r 7+7+7+*&*&.:l.l.l.l.l.6@6@6@6@@>u*@>6@P&m%m%o=Q;#=0OC:~ON=b*j qo,X!+A;A;A;H%A;A;H%H%H%H%`O`O`O`O. . . . . . . . M$M-M-M$M$M$_o_oM$_oz,z,A=A=A=A=z,z,a#a#A=a#a#WXWXa#A=a#. },y+},^>,XH%A=f+<=}OK=t>0:h@0:0:A*h@h@t>A*)X)XK=N,Z$Z$N,F-#. r&i@L@H. ", +" P%g>j*P=*.+;7&A:A=hOF-h@6XL;4*)$<@/-T,G#V@F&p;t$vXu**&|$;ov:m%l;o=W h&z,q>0:H$s>s>s>P*z@r:r:z@z@h& OrXY=5${.)$T,T,)$;O)$6 6 6 +&+&+&<@7*y=e;oo9=X+c#-;Q@s,WXT,m%m%l;o=r `-|$`-`-r r r r 7+7+*&.:*&.:.:l.l.l.l.6@6@6@@>u*u*@>u*@>l.m%m%m%P#Y:JX~##=C:~Ol$N=b*u@&:y+y+7&y+7&7&y+y+y+j y+j j j +;j +;j j +;+;+;-%+;+;-%+;+;-%-%-%tO-%-%tOtOtOtOtOtO},tOtOtOtO&-_#},b*s,N=TXb*b*C.+;^>H%N*,-L;Z$t>h@0:h@0:L.h@h@A*t>)Xc#c#c#K=K=[o,.s@&:>:!=7+m%l;o=),7+*&@>d=t$z%{.#o_=)$+&kX:#7*3-]>}OY:N**.-%7&==_o-;)Or.!% ", +" G$r*'*`O-%j Q@M$-;}Oh@}O[oH y=>+>+/-_=(*j:z%Kod=u**&4O -o=I+l;v:@>A#% A;% Q;n#{Xz@P*P*P*E.Y=5=~%Q$6 T,;O_=;OT,;O;O;O)$/-6 >++&';+&';7*y=BO$OmO~:}ON*&-lm%m%I+),`-`-r |$`-r r r 7+.:.:*&.:.:l.l.l.6@6@6@6@u*u*u*@>@>vXvXu*7+m%m%m%2#!+Qo[,O-~##=(&E+E++.A%A%A%A%~O~O~O~O~Ol+;,Xz,hO,.[ot>h@0:0:0:L.A*A*A*A*A*c#K=c#c#N,Z$]@*.&-a&s.G@m%+X;o),r u*0,t$u-W {.G#;O>++&{:y=,,go6XL;ioa#}&+;y+A:WX0%m:;=^% ", +" v >Z-a#&-j &-A;F.Y:A*h@Z$3-!=/-+&/-;O#o{.p;e<0,vX6@r ),;ov:' ' |$+&rX_#hO+$n#P*P*P*n#X+Q;9=6 >+_=V@(*_=G#G#T,;O/-)$)$6 6 6 +&';';<@{:,,e;T-r:+$Y:_oj (&_:m%m%m%v:|$r r r 7+7+7+7+*&.:*&.:l..:.:6@6@6@6@u*6@u*u*@>vXvX@>vXd=u*;om%m%l;j:3-hOL;L;L;U%% F-Z$Z$Z$F-Z$Z$F-F-F-[oZ$Z$Z$Z$[oZ$[o[oZ$[o[o[oZ$N,[oN,[o[o[o[o[o[oN,[o[o[o[o[o[o[oN,[o[oN,N,[oF-F-Z$F-F-F-Z$F-Z$t>hOC.b-&:^>_o#<,.[oh@L.0:a&0:0:h@A*h@t>)Xc#c#K=K=K=F-hO+;`O6;z%I+l;G@P#4O.:6@2#t$e+<@:#kXH,9%L;,.-;M-^>-%tO!+N*C G;|- ", +" $ )@w=y#==+;j !+a#}#N,0:`+%*iXT,s.>+;O#o{.W eZOcoA=_ot>L-s>~%Q;y%V+';/-p;F&V@C>C>G##o_=;OT,T,;O;O)$6 6 >++&';<@7*,,V+);n#a&#<*.&:TXs.m%m%m%G@7+r 7+7+7+*&*&.:*&*&l..:l.6@6@6@6@u*u*@>u*@>@>@>2#2#2#vXKo@>v:m%m%m%L>@>Ko2#d=d=2#d=2#vXvXvXvXvXvXvX2#vXvX2#d=2#d=2#d=d=2#2#2#d=2#d=vXvXvXvXvXvXvX2#vXvXvXvXvXvXvXvX2#vXvXvX2#2#vXd=d=d=vX2#2#2#2#vX4OS,7&M;b*^>A=#<,.K=h@0:0:a&a&0:L.h@h@t>A*A*t>)Xc#K=%*A=7&]>V+`-m%I+L> -r .:@>d=t$z%F&(*_=;O+&7*:#,,{X[oF-,.>:*._#y+_#`O>:SOa-K& ", +" 4,1=y$A;tO7&==M$-;U%A*%*6X%,)$s./-;OG#V@D+ZOu-0,u*.:`-P#o=' l;v:.:e;N,,X]>goY=Q$:#<@F&KoD+{.{.V@(*C>#oG#_=_=T,;O;O)$/-6 6 /->+';s.{:5$W*$#; )Xf+Q@TXa#W m%m%l;P#.:r *&.:7+*&.:l.l..:6@6@l.6@u*6@6@u*@>@>@>vX2#2#2#d=d=2#0,u*l;m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%L.+.A%&:Q@WXio% c#L.0:0:L.0:0:0:L.h@h@A*t>)XK=K=N,io,X,X.#T,+Xm%I+;o),r 6@2#t$eM-&-j &-H%F.Y:t>F-}Os>9+)$T,#oF&z%u-0,@>6@`-),;oP&m%I+),G#Y=*.]@mOBO{.@>e+>+';<@kXBO!=8- @% WX},l$go*&m%m%v:|$.:*&*&.:l.*&.:l.l.6@l.u*u*6@6@@>vX@>vX2#vXvX2#0,2#d=d=0,d=`-m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%l;m%m%m%m%m%m%m%m%m%m%l;l;l;l;l;l;l;m%l;l;m%m%m%m%m%m%m%m%m%l;l;l;l;l;m%m%' m%+Xs@5ol$j *.>:6XF-t>L.a&L.0:0:a&0:0:h@h@t>t>t>)Xc#F-f+y+q>@@0,' m%+XP#|$*&u*0,u-ZOW {.G#;O>+s.:#,,w-a&Y:,.#W+k.Y# ", +" ^%P:%;a#==+;-%}&WX]>K=h@}Oc#4*6 s.6 ;O_={.p;eKo, hOU%, D+ZOF&F&D+D+j:{.j:(*(*#o#o#o#oG#)$;O;O)$;O)$6 >+6 ';<@{:e;Q$M++$6XM-j A%b@I+m%m%G@*&*&.:*&.:l..:l..:6@6@6@6@@>@>u*@>@>@>vX2#vXvX2#d=d=d=0,t$0,7+o=o=o=L>o=o=o=o=o=L>L>L>o=o=o=L>o=L>L>L>L>L>L>;oL>;oL>L>L>P#;oL>;oL>;o;o;o;oP#;o - - - - - - -P# -),P# - -P# - - - - -),),),4O -v:m%m%m%BO^>T@N=},`Ob %*N,h@L.a&a&a&a&a&0:L.A*t>A*A*t>)Xc#,.M-7&F-:#4Om%P&;o -r l.@>d=e ", +" $ &%^*f+}&-%y+Q@_o-;% 0:,.ioH +&s.+&;O#oV@j:ZOKoKo@>.:`-P#G@I+m%I+*&7*=#oG#_=T,;O;O)$)$/-6 6 ';<@y=v&u.s>a&,-!+u@TXp;m%m%l;L>u*.:.:l.l.6@6@6@6@6@6@u*u*u*@>vX@>@>vX2#2#d=d=d=d=Ko0,0,Ko0,vXvXvXvXd=2#2#d=2#2#2#d=0,Kod=0,Ko0,0,t$u-t$t$t$ez,,-L;)Xh@a&c+V c+0:a&0:0:h@A*A*A*A*t>N,#<&-A;n#D+v:m%+XP#4O7+l.2#0,u-W {.C>T,6 ';{:y=w-V L;F-]@N*!+-%y+,X_o-;do&;T+ ", +" N#Do>O. &-&:qoH%r&`+)X[oL;L-V+<@+&/-;O(*{.D+eI+' l;;oz%%,A=U%Q$#oW D+j:D+D+{.{.j:(*C>(*C>G##oG#T,T,;O)$;O;O/->+>+7*,,W*9=; )X>:^>7>s@l.m%m%l;),u*l.l.l.u*@>6@6@u*@>@>vXvX@>@>vX2#2#2#d=d=d=d=0,KoKot$t$t$t$u-eC>(*C>G#G#_=_=_=G#G#T,T,T,;O;O)$;O;O/-/-/-/-6 6 6 >+>+>+>++&+&+&';';:#G#o=m%m%m%6XT@~OC.,Xq><=% )XL.c+c+V a&0:a&a&0:0:h@A*t>)Xc#U%_oC.<=V+*&' I+o= -4Or vX0,t$e+s.kX,,v&K=6X`+#<=K=0:N,Z$cos.+&6 )$G#j:D+z%Kod=@>*&|$ -o=' m%+X.:5$)X3%; {:F&D+D+{.F&F&{.{.(*C>(*C>#o#oT,;O;O;O)$;O;O/-+&+&{:9rX4Om%m%v:*&6@l.6@6@6@u*@>@>@>@>vX@>2#2#2#2#d=d=d=d=0,KoKoKoKoKot$t$u-eC>#o#oC>C>#oG#G#_=_=_=_=G#T,T,;O;O;O;O)$)$/-/-)$/-/-/->+';z%v:m%m%),H%O-^o+;A;>:6XZ$h@c+c+a&V V c+a&a&0:L.t>t>A*A*)X,-qo==rXV@v:m%P&P#),r l.2#0,u-z%F&C>_=)$+&{::#9i+x-I ", +" P%wOX$b }&tOy+Q@z,3%% L.% #F&p;e<0,vX6@`- -P#v:m%I+;oF&y%a#}OooC>F&F&j:D+F&{.{.{.(*(*(*C>G#G#_=T,T,T,;O;O)$>+';kXBO$O6;3-]@`O&:s,v&v:m%m%L>l.u*u*6@u*@>@>vX@>vX@>vX2#d=d=d=d=d=d=0,0,0,Kot$t$t$u-u-u-u-ZOeC>C>C>G##oG#G#G#_=_=_=_=T,T,;O)$;O;O)$/-)$/-/-6 /-6 >+>+s./-@>' m%m%e;tO#=p#&-M--;`+K=0:V V V c+V c+0:a&0:L.0:A*A*t>Z$a#&:,-x>l.m%' o=P#4O*&u*d=t$ZOD+{.G#T,/-<@kXkXV+A*L;[o]>WX}&-%y+==M$r&0%$$8# ", +" 3OA-ro. &-7&qoH%F.%*A*K=,.~%p:7*s.6 ;O#oV@D+ZOt$2#u*.:4O;oG@l;l;v:*&d%,.3%s>';F&D+D+j:D+F&j:{.{.(*(*C>#oG#_=T,_=_=)$;O;O+&';{:e;$+z@V ,-!+TXu@l.m%m%' ),@>u*u*@>@>vXvXvXvX2#2#2#d=0,0,0,0,Ko0,Ko0,KoKoKot$e(*(*C>G##o#o#oG#G##o_=_=_=T,;OT,T,T,;O;O)$)$/-/-/-6 6 6 6 6 >+>++&kXT,4Om%m%m%~%^o+.7>qoA=ioU%)Xa&1;1;1;1;1;c+a&0:a&0:L.A*A*)X6X,X&-+$#oo=l;+XL>P#r l.@>Kou-z%j:{.G#)$+&<@kXy=b@[oY:,.hO_o,X+;j !+q>X&^XQ,s# ", +" P%};a*WX^>j +;}&WX]>N,a&N,% 6;<@+&6 )$G#(*j:ZOt$d=u*.:`-),L>P&m%P&o={.{XN*Z$v&(*D+F&{.W D+{.{.j:(*C>(*C>G#_=_=T,T,;O;O/-';7*:#v&iX Ot>r&qob*F.P#m%m%I+r 2#u*@>vXvXvX2#2#2#2#2#d=0,0,KoKoKoKoKot$t$t$e(*(*C>#o#oG#G#G#G#G#_=T,_=T,T,T,)$;O;O)$)$)$)$/-/-6 6 6 6 >+>+>+>++&+&y=C>G@m%m%I+ioT@l$y+A:N*]@F-A*c+1;9%1;1;c+V c+0:a&a&h@A*h@K=s@7&-;T-6@l;l;G@;o4O*&u*2#Kou-W V@(*T,>+<@<@kXe;z@N,% 6Xr&`O_#j &-`O>:l,B;e%P% ", +" e%s*0%*.},7&==M$-;L;h@Z$#{.W t$KovX6@*&4OL>G@l;' +Xl.v&]>r&M++&D+F&j:F&F&j:j:{.V@(*(*G#_=_=G#_=T,T,;O)$>+7*Cox>co0.F-a#y+u@~:o=m%m%v:.:2#vXvX@>2#2#2#d=0,0,d=0,KoKo0,Kou-KoKou-e(*C>C>#o#oC>G#_=#o#oT,_=_=_=T,;OT,;O)$)$)$;O/-)$)$/-6 6 6 >++&>+>+>+';+&';s.{:p;P&m%m%vX}&O-N=-%A;r&`+N,0:1;1;9%1;1;V V a&L.0:0:0:L.A*`+,XtO=Kot$ZOj:V@#o;O>+<@y={:p:K=,.F-}#a#*.-%y+,Xz,-;*OU+P% ", +" 47&},H%s@]>K=N,6X+,!=7*';6 ;OG#V@F&ZOu-0,u**&r P#G@I+m%P&;o(*L-F.N,p:(*F&j:{.j:F&j:j:{.(*(*#oG#G#G#T,;OT,T,/-6 7*w-H,6;go6X. b*u@CoP&m%m%P#@>2#vXvXvX2#d=2#d=0,Ko0,0,Kot$Kot$u-t$u-u-e(*V@C>C>#o#oG#_=G##o_=_=G#T,;OT,T,T,)$;O;O/-/-)$/-/-/-6 /-6 >+>+>+';+&+&+&s.s.';{:';vX' m%l;b@C.T@TX&-M$hOU%t>c+9%9%9%1;1;1;1;1;c+0:0:L.)X% s@y+b [%l.m%l;G@;o),7+6@2#t$u-W j:(*_=)$>+7*y=:#Q$}OY:`+-;M$Q@j -%A;N*:oM&5% ", +" P%k@R&s@A:+;y+Q@A=,-% h@N,`+s>7*+&>+;OT,(*F&W eG#_=_=T,T,T,/->+:#e;, s>V ,-}&p#tO -l;m%l;r d=2#@>2#d=2#d=0,0,0,0,t$t$Kou-u-t$u-u-ZOe#o(*(*#oG#G#G#_=_=G#G#T,_=T,)$;O)$;O)$)$/-)$/-6 6 /-/->+6 >++&';+&';';s.';';<@s.y=)$4Om%m%o=+,A%+.C.Q@A=}#F-L.V 9%kO9%9%1;1;1;1;c+h@t>)X)X% a#^>+$_=+Xm%P&L> -|$7+@>Kou-ZOD+V@G#T,6 ';kX7*V+X+F-,.]>s@*.tOy+^>M-r&S.-:6Xh@c##<.#BO';s./-T,#oV@F&z%e.:`-P#;ov:l;' L>V@ ON*%*H,_=F&{.V@F&{.V@j:V@(*V@(*G#_=G#_=T,;O/-+&y=v&4*Y=A*>:},^of+l;m%m%' .:t$0,d=d=d=0,KoKoKoKoKot$t$t$t$u-eC>#o#oC>#oG#_=T,_=_=T,_=T,;OT,)$)$;O)$;O/-/-/-6 6 6 >+6 >+>+';s.+&s.';';s.<@s.s.<@CoV@+Xm%m%*&f+5ol$+;!+N*]@N,0:1;1;kOkOkO1;1;V 0:L.L.c+.#H$.#r&io);.:m%' G@;o|$7+l.2#t$e/ ", +" R$9;yXa#Q@y++;}&a#}#[ot>U%[oH kX>++&;OT,#oF&W u-KovXl.*&4O;oG@l;m%' .:9Q;d%(*j:{.j:j:j:{.V@(*V@(*G##o#o_=_=)$>+';:#W*%,; Y:==b-s,X+I+m%l;G@u*Ko0,0,Ko0,KoKoKot$Kou-t$t$u-u-u-e(*(*C>G##o#oG#G#G#G#G#T,_=_=T,;O;O)$;O)$)$)$/-/-/-)$6 +&+&6 >++&>++&';s.s.s.<@s.s.<@7*7*7*y=z%I+m%m%{.},[,TX&-. f+`+)Xc+9%9%=Q;(*P&m%v:o= -7+l.vX0,t$z%D+(*_=T,/-+&7*7*d%P*L;Y:Y:>:`Oqo7&&-M-r&]>e@$. ", +" A DOs@*.tOj qoM$-;%*t>c#3%+$w-6 ';/-)$G#j:F&e$+&{.j:F&D+j:j:j:V@(*(*#oG##oG#_=)$>+>+{:, rXY:H%b*#=C.kXl;m%m%),2#Kod=0,KoKo0,Kot$t$t$u-e(*C>C>C>#o#oG#_=G#_=T,_=_=T,;OT,T,)$/-)$)$6 /-6 /-6 >+6 6 +&';+&>++&';';';';<@s.s.<@7*<@7*7*kXs.vXl;m%' T-s,#=b*qoz,,-}OA*1;kOkO=<=<9%c+c++,coBOs.j:)$Y=z,`+b@),m%' o=;o4O7+6@2#0,e+s.y=+&[%[oL;U%,-WX}&+;+;Q@z,f+J.w:D% ", +" >*Y+`oFo^>j tOA;N*}#N,t>%*t>%,{:+&>+)$;O#o{.W eG#j:j:j:F&j:j:{.C>(*#o_=_=G##o{.(*$Oh&go,-}&+;TX#=_#|$m%m%l;*&d=t$Ko0,KoKot$t$u-u-e+>++&+&+&';';+&+&s.s.s.s.<@<@s.7*7*7*7*7*Co)$|$m%m%|$=<+.M;C.Q@q>]>Z$L.9%=<3-V A*kOS,T-BOV@*&u-)$iXL;a#M+ZO' m%P&L> -r .:u*d=KoZOD+{.#oT,6 +&7*:#,,h&6X6X%*r&. ^>y+},*.s@}#n>;; ", +" l-B=z+`@,X-%j ,X_ob L;L.K=}#+,Co/-s./-)$T,V@j:z%Kod=@>l.`-P#L>v:l;m%G@t$, %*q>P*kX{.{.j:F&j:j:V@C>C>G#(*eH%-%l$(&-;P&m%m%' @>u-t$Kot$u-u-u-e(*(*(*C>#o#o#o#o#oG#_=_=_=G#T,;OT,T,;OT,;O)$)$)$/-6 6 /->+>+>+>+>+';';+&';';s.';';<@s.<@7*7*7*7*{:kXkX{::#:#kX9<(*+Xm%m%Ko>:T>l$j *.>:%*K=V 1;0:0:rX9=A#{:u-vXZOW (*v&=T,)$+&s.:#>+[%L.,.U%}#WX*.},-%^>M$l 2@P$`: ", +" K.D=hOM$qo7&},`ON*io)X)X6Xh@@@{:';+&)$;OC>j:W ZOKo2#6@*&4O -G@v:l;P&),;OQ;A=L;);T,j:{.{.j:V@{.{.D+vXF&,,H,s>a&U%L;Y:}#q>}&y++.s,Q;P&m%m%o=0,ZOu-u-eC>C>#oG#G##o#o#o_=_=_=T,_=_=T,T,T,;O)$)$)$6 >+>+>+>+>+>+>++&+&';';s.';';s.s.<@<@<@<@7*7*{:kX{:kXkXkX:#:#,,y=y=,,Co,,9),r *&@>0,u-z%F&(*_=;O6 s.7*y=7*H Y:Y:`+f+M-,Xj tO!+N*hO*:eO3. ", +" !%P@N.t=,Xj j Q@_ob L;L.K=6X+,y=/-s./-T,_=j:W p;t$0,6@l.|$|$L>G@' l;v:@>p:c#M$5=e;V@j:(*V@p;d=e<6 Co_:rXt>% F-% U%Y:-;_o==&:T>j y=l;m%m%G@|$7+r 7+r `-r 7+7+7+7+7+7+7+.:.:l.l..:l.l.l..:l.l.l.l.l.6@6@6@6@u*@>u*u*u*@>u*@>vX@>@>@>@>vX@>2#2#2#2#2#2#2#2#2#2#KoKoKoKoKoKoKo0,0,KoKoKot$KoKoKot$t$t$t$t$ZOu-u-e:Y:9%s>);s.t$t$t$u-ZOz%ZOp;T,Q$N,a#; T,G@m%P&L> -`-7+6@2#t$ZOW F&#oT,;O+&s.kX+&T-kOL;,.}#WX*.&-y+qoM-l ,&E&4: ", +" D%F%s@M-_#7&},A;q>}#t>t>]>t>Q$<@7*>+T,_=(*F&W ZOKo@>@>*&r -L>P&m%l;P#F&8-#{:F&t$2#(*{:b@z@9%Z$F-Z$Z$Z$F-,.<=r&`O&-b*0OA;`-m%m%m%l;l;l;' l;l;l;l;l;l;l;l;l;l;l;' ' ' ' ' l;l;l;' l;l;' l;l;l;' ' l;' ' ' ' ' ' ' l;' ' ' ' l;' l;' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' I+I+' ' I+I+' ' I+I+' I+I+' I+' I+' l;m%m%r 3-(&+.C.^>N*}Ogo[%_=D+ZO0,0,ehO4;moD% ", +" 8#>o|,i-Q@+;+;Q@M-r&U%A*Z$U%rXCo+&<@)$T,G#V@j:W u-d=2#l.7+|$),G@I+m%P&7+6 ~%M$<=_:6 _=kX%,.#0:% U%}OZ$[oc#[oF-`+}#s@*.-%l$#=U%+Xm%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%j:N*O-l$&-_o}OE.b@';{.p;p;ZOe2#t$ZOW {.C>_=)$+&s.y=';x>go`+`+ioA=}&},y+^>M-q&D>9${@ ", +" 4,qX]*M-qoy+},*.WX,-K=t><=F-$+';s.>+/-T,G#V@W ZOt$d=@>l.7+r ;o+X' m%+Xl.5$0:A;[o{XY=1;% L;U%}OZ$K=[oZ$N,[o}O%*hOa#A:j E+b*y%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%m%,,&:O-C.WX[oX+u.5$6 _={.p;z%ZOz%W W W /-%,<=s@s>(*;om%v:o= -|$*&u*vXKoe:`+)XF-,.=+)$_=(*D+ZOZOt$2#@>.:7+ -o=v:m%m%o=d=oo% &-}&hO%*L;F-Z$N,Z$[o[oZ$[oZ$U%6Xb _o==&:(&tOL-v&W*x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>oox>x>x>x>oox>x>x>x>x>x>x>x>x>x>x>x>A#oooox>x>W*x>W*W*b@W*W*W*b@W*b@W*W*W*W*W*W*b@b@W*W*b@W*b@b@W*W*x>x>x>W*W*x>W*W*W*W*b@W*W*x>W*x>W*x>x>W*x>x>W*b@W*x>x>x>W*W*x>W*W*b@9<+$b-^o!+,-1;E., BO+&#oF&p;z%ZOz%z%W #o$O)XN*kO6 4Ol;' L>P#|$7+l.vX0,u-z%D+j:C>T,6 ';{:y=7*T-kO`+%*}#WX*.&-7&^>M->:x%L%H*^% ", +" P%so!o:.M-_#y+},*.a##%*% iXy=<@s./-_=C>V@p;p;ep#}&]@Z$Z$F-Z$[oN,N,Z$F-Z$L;]>b M$==C.b-b-b*u@7>TXTXTXTXTXTXTXTXTXTX7>TXTX7>TX7>TXTXTX7>7>7>7>7>7>TXTXTX7>7>TX7>7>TXN=p#7>u@C.C.u@u@C.C.C.u@C.u@u@u@u@b*b*b*b*u@u@u@b*u@u@u@u@u@u@b*b*b*b*b*b*b*b*b*b*b*u@u@u@b*7>7>7>7>7>b*7>7>b*b*b*7>7>7>b*b*7>TX7>b*y+7>p#&-a#`++,6;A#,,/-#o{.D+p;z%z%p;{.V+.#WXL;e;r ' I+P&P#),r l.u*2#t$ZOz%j:C>G#;O6 s.:#,,7*X+Y:,.%*r&. ==j },}&WX!,=:~oso ", +" 8#o<:.F.,X+;7&qoM->:6X)X)X,.N,x>s.';/-T,T,#oF&D+ZOKo0,@>l.|$),L>v:I+m%v:4O)$; Q@&:WX`+F-F-F-F-[oN,[oZ$Z$,.]>f+z,Q@j TX~O=X5o~#5o~#5o~#~#~#~#~#O-5o5o5o5o5o5o5o~#5o5o~#5oT>5o5o5oT>T>T>5o5oT>O-O-5o=X(&(&(&E+E+(&C:(&(&C:(&C:(&C:=XC:C:C:=X=X=X=X=X=X=X=XT@=X=XT@=X=XT@=XT@T@=XT@T@T@T@#=T@T@=X#=#=#=#=#=#=#=T>#=#=#=#=#=#=5o5oT>C:E++.A%N=tO`O3%)XX+%,b@{:;O#oV@D+F&p;W j:kXP*s@-;4*0,I+m%P&G@ -4O*&u*vX0,u-p;D+V@_=T,/->+7*:#<@y%A*L;%*,-a#}&-%7&Q@M$r&#< .H*G$ ", +" P%0$#:b+H%^>j +;}&z,3%% h@L;`+n#e;s.+&6 )$G#{.j:p;u-t$2#u**&4OP#G@v:m%l;+X.:w-h@u@y+-;L;F-Z$[o[oZ$Z$F-U%,.<=-;q>!+tO7&b*TXp#s,N=s,N=s,s,s,s,s,s,N=N=N=N=N=p#N=N=N=p#p#p#p#p#TXTXp#7>7>s,b-^o&:j j -%tOtO-%-%-%-%j +;-%+;+;+;-%j +;+;+;j j y+j j y+y+y+7&7&7&7&7&7&&:&:&:7&&:&:&:C.C.C.C.u@C.C.u@u@u@u@C.C.C.u@b*u@C.7>s,s,&:-%-%tO&-_#^>A:M-b U%goE.[%e;s.)$G#V@j:F&j:F&6 iX<=F.S,(*o=m%I+o=;o4O*&6@@>0,u-ZOF&j:C>T,)$+&s.{:y=9<~:`+,.]@s@H%_#&:&-!+WXJ#y E:k@ ", +" I S#:.r&}&-%y+_#H%F.6Xc#t>`+U%Q$s.<@';/-T,(*V@W z%u-Ko2#6@7+4O;oG@' ' l;G@t$Q$]@p#},,-U%F-Z$Z$[o[oF-}OU%<=#C>C>{.V@/-$+K=N*kOkX),m%m%v: -),r l.2#0,u-z%p;j:C>_=)$6 s.kX{:<@ OZ$% ,.,-_oQ@-%j Q@M$b ,-j@{,!% ", +" KO=,i,H%^>y++;,XA=#<}O0:Z$L;goW*s.<@>+/-G#(*{.W z%u-0,@>.:|$),P#o=I+l;I+P#j:>$b TX^>io}OZ$N,N,[oZ$F-F-`+<=-;q>z,M-A;*.A;!+!+*.*.*.A;*.H%H%A;H%H%H%H%`OH%. . `O. `OM-_o`OQ@Q@z,hOio%*U%U%L;,.,.,.%*%*`+`+`+6XY:]@]@]@<=]@<=]>]>]>ioioioioioio}#,-,-}#}##<#:r&>:r&r&F.s@r&r&F.A=!+_ob #<<=`+`+%*`+,.U%}O% Z$K=0:5=S,3(*/-Q$1;s@t>(..:l;l;+XL>P#4O*&u*0,t$ZOW W V@_=;O/-+&7*{:y=$+c+%*L;]@F.A;},7&_#*.q>B..=5:>* ", +" I ;@O:(#*.tOy+&-A;s@]>[oh@L;]@co:#<@+&/-T,#o{.F&p;u-t$2#6@7+|$),;o+XI+m%' 4OG#M+s@7>,XioF-N,N,[oZ$F-% U%`+]@#:s@s@s@>:F.f+f+f+f+f+f+f+b b 3%hO-;q>_ohO% )X1;;*~:rXrX~:.#5=+,gogo3-+$+$3-3-kOkO9%9%1;1;1;V V c+c+a&a&a&L.L.0:h@A*A*t>t>t>)X)Xc#c#c#K=N,[oN,N,[o[oZ$% % % % Z$Z$Y:b ,-L;F-K=kO3-=<3-gogogo5=~:;*~: @X+Y=h&$#Q$V+Co<@>+;O_=#oC>6 Q$3-N*% , d=' m%v:o= -4O`-l.@>Koe)$/->+s.kX7*,,;*,.,.6X-;_oQ@+;j A:z,3%<=;X{@!% ", +" P%k@3 B&a#A:j j ==M-f+Y:)X[o%*L.$O6 <@+&)$_=V@V@D+ZOZOd=@>l.r `- -o=v:' m%I+|$;Os>WXb*}&}#% [oN,N,Z$}O% }O,.%*]><=<=ioio]>io]><=<=<=]@]@]@6X6XY:Y:%*`+`+,.`+]>,-Y:h@3-X+mO9=>$3P*{Xn#n#Y=Y=S,S, OH$ OL-X+~%X+~%~%Q; @ @;*;*;*~:~:.#rX.#go+,go+,+,gogo3-gogokOc#F-h@V kO0.{X{Xn#n#s>z@E.E.h&H H y%mO3+6 G##o>+Q$gos@%*4*u-P&m%P&L>P#|$7+.:@>d=t$ZOW j:(*G#T,/-';{:<@y=3<[o6X`+# ", +" 8#uXfX<&`Oqoj -%}&a##+;OG#C>{.D+p;t$0,2#l.7+`-P#o=+Xl;m%P&7++&Y=A=u@A;<=F-N,N,Z$F-% Z$F-U%}O,.L;L;L;U%}OU%F-Z$% F-Z$Z$[oN,N,K=N,K=[o,.F-=A#A#A#H,$OQ$Q$T-, , $+[%u.@@@@4*4*iXiXiXiX$#9=coco>$8-3<3s>{Xs>{XY=Y=S, O OS,n#S,5=3-gogo+$Y=co3<3p:d%5$kX';+&>+/-_=+&!=+,F.ioiXp;G@m%P&L>P#|$r .:vXd=0,eF.. ^>y+-%}&a#X&,`. ", +" Z>r*4.s@H%},7&_#H%s@io[oN,}OU%r:kX<@s.>+/-_=#oj:D+p;t$d=vX.:*&`- -o=I+m%m%+X.:s.L-M$C.H%io% Z$F-[oF-[o[oN,Z$Z$[o[o[oN,K=N,t>A*c#t>A*A*A*L.L.h@K=t>9%.#n#oo';<@y=5$Co5$w-BOd%e;U U V+v&v&p:b@W*W*x>A#H,!=!=H,$O$OQ$, , $+[%););@@@@4*_:_:iX$#$#9=%,%,>$3<8-3<3:-;9=j:o=m%I+G@;o4O*&.:u*2#Kot$p;F&(*G#T,6 >+<@:#<@U H$}O%*6Xf+_o,X+;j ==M$r&,=f;NOO> ", +" Zo[+4 z,==+;+;Q@M-f+<=t>Z$%*a&[%s.s.s.>+;O_=(*{.D+e<0,d=u*l.7+4OP#;oP&m%' o=l.s.Q;H%7&H%io% Z$[oZ$[oN,[oK=K=c#)Xt>)XA*A*t>A*h@0:L.L.h@0:L.1;.#X+9=>+(*6 +&+&<@7*{:{:kXy=,,Co5$w-9<9$cocomOr:P*Y=+$.#co4*@@@@u.u.$+T-Q$T-H,!=H,A#W*(.(.p:U d%d%d%9++&kXQ$+$F.F.8-#o),l;l;o=P# -`-.:u*vXKou-W D+V@_=;O;O+&s.{:7*,,H }Oio`+,-WXA;},j },*.s@T#t;g;G$ ", +" P%)&y:'+`Oqo7&tO}&A=b %*0:[oio5=v&s.<@';)$;O#oV@D+ZOt$Ko0,u**&`- -P#o=I+m%I+o=6@{:Q;. 7&A;]>}OZ$[o[oK=K=c#c#c#c#)Xt>t>A*t>h@L.h@A*L.a&3-rXmO';(*_=)$/-6 >++&';<@7*{:{:{::#y=,,Cow-5$9$#$#$#$#4*4*u.);$+, T-$OH,H,!=x>b@W*b@p:U e;e;9<5$5$Co:#{:{:<@';<@Cou.3-N*s@8-G#|$l;l;+XL> -|$*&l.@>0,t$ey++;}&a#hO_&/X1*v ", +" 5V@W ZOet>)XA*A*h@L.L.0:3-{X(.F&C>_=T,)$)$)$)$6 >+>++&s.<@7*{:kXkXy=,,CoCoCow-w-BOe;d%V+V+V+V+v&p:(.b@W*x>A#A#!=!=H,$OQ$Q$T-$+[%[%);u.4*4*_:_:iX9=%,co0.L.0.3<8->$8-%,$#iX_:_:);$+[%[%T-$OH,oooox>W*(.V+v&V+e;9 -4O7+u*@>d=t$ZOp;{.C>G#;O/-+&7*:#+&Q$=<% ,.]@f+M-Q@y+j ==M->:]>;-I$8# ", +" cO5.B.M$^>j j Q@M$f+<=c#N,U%)XP*s.{:+&6 )$_=C>{.W z%ZOKo@>u*l.`-4OP#G@' m%I+L>6@';{XN*C.}&hO}ON,K=N,N,)X)XK=)XA*A*A*A*t>a&rXT-#oV@C>C>V@C>G#T,;O;O)$;O/-/->++&';<@7*{:kX{:kXy=,,,,Co5$9<9x>ooA#A#H,H,$OQ$, $+$+[%$+[%u.@@@@@@H$kO+${XH 6;3<>$>$>$9=_:_:_:4*);$+$+, Q$Q$H,!=oox>b@p:v&v&U d%BOBOw-,,5$,,y=:#,,U coL.WXioco(*4Ol;' I+L> -4O*&u*2#0,u-z%p;D+V@#o;O/-6 <@:#{:d%P*F-]@%*#+)$_=(*F&W z%u-d=2#u*`-4O),P#+X' m%' L>*&>+P*f+u@A:hO,.F-[oK=c#c#)X)Xt>t>[o3-M+kXC>V@D+j:F&(*C>_=_=G#_=T,;O;O)$6 6 +&+&';<@7*{:kX:#y=,,,,Co5$w-9x>A#H,H,Q$T-Q$T-$+$+$+T-Q$cogo1;L-s>E.H 6;y%mO8-8->$9=9=iX_:4*@@$+[%$+, $O!=A#A#oob@b@(.V+U e;e;d%w-5$5$5$y=w-b@6;K=z,%*$#j: -l;' P&;o),|$r 6@2#d=0,ZOp;D+V@C>T,/-+&s.kXy=<@coF-6XL;]>N**.qoj -%Q@z,3%c%W-8=^% ", +" D.<:2Xn@!+},&:},!+a#-;U%t>Z$6Xgo,,{:<@+&6 T,G#{.D+W e+X' m%' v:|$T,H #F.Y:Z$c#K=[o[oK=1;L-p:>+G#e#oG#T,;OT,)$/-6 6 6 +&';';<@kX{:kX,,,,,,,,,,Cow-BOBOe;e;V+U U v&p:p:b@b@x>ooA#ooA#H,H,$OQ$Q$T-A#_:X+3-;*; ; P*E.r:H 6;6;y%3<>$co>$$#iXiXiX@@);$+[%, Q$$OH,!=A#x>b@p:V+U U d%d%9<9m%l;P&L>),4O|$l.@>2#KoeF.`O==y+j ==. r&]@2@PXh. ", +" _,k><%,6Xy+-%A=]@U%U%c#rX8-{:6 eW*x>x>ooA#!=!=H,A#H,r:5=~:~% @; s>r:E.z@z@h&6;6;6;3<3<>$co9=$#$#_:@@u.);[%$+T-Q$H,!=A#x>b@p:v&V+e;U U e;BO9 -4O|$l.u*2#KoZOz%D+{.#oT,;O>+s.7*:#<@H,3-,.,.6Xf+M-,X+;7&_#*.N*yOb=3$w& ", +" P%q<( S:`Oqoj j ==. s@ioN,A*%*% s>:#';s.+&)$T,G#{.D+p;ZOu-d=vX6@r r |$;oo=v:m%m%I+ -j:, Z$==&:`O`+L-!=kX#ou*2#e(*#oG#_=_=T,;O)$/-6 6 6 >+';<@<@{:kXy=y=,,,,Cow-w-5$BOBOe;e;e;V+U V+v&b@W*b@x>x>oox>W*x>co~%0.~:3-.#S,s>{X{Xs>P*z@r:h&H 6;6;6;mO>$>$9=9=$#4*_:@@);$+$+, $OH,!=A#ooW*(.p:v&U V+V+U U ooM+t>_os@= -|$r .:u*d=Kot$W W j:(*T,)$/-';{::#:#v&L-}O`+]@3%a#!+},y+},!+WXi*R>'O$X ", +" G$O*R=n@A;_#y+tOQ@M->:6Xc#Z$,.Z$H y=';s.6 )$T,#o{.F&D+ZO0,d=vXl..:`-),P#;ov:l;m%I+o=t$d%rXa#A:Y:%,#od=t$F&z%z%eC>_=_=_=T,T,)$/-6 6 6 +&';s.<@7*{:kXy=y=,,,,,,Co5$9z@E.E.h&6;6;6;3<8-8-co9=$#4*4*4*););[%, $O$OQ$!=oox>W*(.p:p:v&V+b@);X+Y:M--;Y=7*6@I+m%P&+X;o;o4Or .:vX2#d=Koz%F&j:C>_=T,)$';s.kXy=V+n#F-Y:Y:,-a#*._#7&tOA:z,hOM ~, XZ>P% ", +" I x-z.l>R#*.&-7&tOA:z,b ,.)X}O`+[o>$,,<@s./-;OT,C>{.{.W e/-6;F-b Z$y%w-C>j:p;W p;ZOp;ZOW D+D+D+j:V@(*C>#oG#T,T,)$)$;O/-6 >++&';<@<@7*{:kXy=:#,,,,,,Co5$9coE. OkOA*5=L-; L-L-L-H$S,n#n#{Xs>z@z@E.M+H H y%8-3<>$>$%,9=iX4*@@u.@@$+, T-T-H,!=A#oox>b@b@p:(.H,y%c+>:A=,.u.V@|$P&l;P&L>;o -4Or .:@>2#Koes@H%_#7&j ,XM$r&<==:v;q% ", +" _,[*5OaXa#!+tOy+},!+a#hO,.L.,.`+A*_:{:7*s.6 ;O;OC>V@F&D+z%u-d=2#@>.:`-4O -;oG@I+' ' +X|$F&Q$N,_o]>L-W*+&(*D+W p;ZOW p;W F&F&{.{.C>(*C>#oG#T,T,;O;O)$6 6 +&+&';<@<@{:{::#,,,,,,Co5$5$w-BOBOe;e;U U U e;V+H,8-r:+,)Xh@~:L- @0.~%X+L-; H$ OY=n#{Xs>P*E.r:r:h&H y%mOmO8->$>$%,_:_:4*@@);[%[%, Q$$OH,H,A#oox>oo!=4*Y=F-_oWX+$e;Koo=' ' +XL>P#4Or *&u*vX0,0,z%W F&V@#o_=)$/-6 7*:#kX9<6;% io}OY:>:. ==y+7&Q@M-F.,-P,{-po ", +" t vOp+M$A:+;j _#*.a#hO}OL.L;Y:1;T-7*7*<@)$)$T,#o{.F&W z%t$2#@>u*l.r 4O -L>+X' m%' +XL>d=w-3-N*3%L.>$9<;O{.z%p;F&D+D+D+F&j:j:{.(*C>C>#oG#_=;O;O/-6 /-6 +&';s.<@7*{:y=:#y=y=y=Co5$w-BO9N,3-~:;*;*;* @0.~%Q;X+L-L-L-S,n#{X{Xs>z@z@E.M+H H y%8->$8-8-%,iXiX_:@@@@@@[%[%T-T-H,A#!=!=H,u.M+3-ioH%r&z@6 *&+Xm%l;I++XL>4Or 6@l.@>2#Kou-z%W {.C>_=T,/->+s.y=kX:#%,Z$,-U%6X>:M$Q@j y+qo`ON*3%*O'oN& ", +" 8#W&U$t,. Q@+;+;Q@H%N*]>}OL.U%<=5=W*';7*>+6 )$T,#oV@j:W z%t$d=vX6@.:*&r ),L>+XP&l;l;P&+X6@+&E.]>A=]@~%, {:C>W W D+j:W j:F&V@V@(*(*#oG#G#_=;O;O;O/-6 6 >+s.<@<@';7*kXy=:#y=,,Co5$5$BO5$Co9d=Kou-z%W {.C>_=_=)$+&s.y=kX{:_:N,io}OY:f+M$}&tOy+&-!+a#b M*D#/%D%P% ", +" C+v$m#q*`O^>y++;==M-r&io% L.U%<= @BO';7*+&/-)$T,#oV@F&p;z%eG@' m%l;G@`-V@Q$kOA=f+Z$z@U ;OF&W D+F&{.j:V@{.C>(*C>G##oG#T,;O;O)$>+6 6 +&';<@<@{:{:kXkXy=y=,,y=:#kXV+x>u.~:Z$t>9%kOkO+$+,go+,5=.#~:~:;*0.Q;Q;X+; ; H$S,Y={X{Xs>E.P*r:M+6;6;6;3<8->$co%,9=iX$#4*u.););[%, , $+$# ON,f+!+r&; e;e -),4O`-.:l.vXd=KoZOp;W j:(*_=;O;O>+7*y=:#+&[%N,<=% Y:-;A=}&&-j tOA:z,-;]@l%xXpo ", +" / /Xm#V#%.&-j tO,XM$>:<=[oh@U%Y:~%Co+&7*+&/-;O_=G#V@D+p;z%e+X' m%m%P&P#Ko,,M+N,`O#G#G#_=;O;O;O;O)$>+>++&+&s.<@{:{:{:y=y=<@s.:#(.(.Y=1;)Xh@c+V 1;1;kO3-3-+$+,.#.#.#rX;* @0.Q;~%X+L-L-H$n#n#{XP*P*P*E.h&6;6;6;3<3<8-co%,coiX_:iX4*u., $+);iXr:9%hO!+A=1;4*)$*&P&m%I+v:G@L>),|$`-7+6@0,KoKoe+;OT,G#(*F&p;ZOu-u-KovXu*l.7+),P#L>G@P&l;' l;+X`-F&b@; ,-_o]@0.Q$<@C>j:F&j:V@(*#o#oC>#o_=T,T,)$;O;O/->+';+&';7*7*7*<@>+7*5$e;u.goL.t>)Xt>L.1;9%V 1;kO=<3-+$5=5=5=rX~:;*;*0.~%~%~%; H$; On#{Xs>s>z@r:r:M+H H y%mO8->$>$9=$#iX$#@@@@4*9=z@+$]@. A;L;H {:vX;o' m%I+G@o=L>P#`-l.l.@>2#Kou-e_=;O/-+&{:kX:#s.$O0:%*,.%*3%a#*.qoj j ==. >:io2=V&6. ", +" z>i&#&-;a#}&tO7&},A:M-F.]>Z$K=L;L;Q;e;s.<@<@>+)$_=C>(*{.W ZOu-t$0,vXu*.:7+`-4O -;o+Xv:m%m%l;+X.:G#_:9%q>z,}O~%[%y=T,V@V@V@C>#o#oG#_=_=;O/-)$;O/-6 6 ';';>+/-6 <@<@A#H$=[oZ$c#A*0:a&a&c+V 1;kOkO3-+$gogo.#~:rX~:;*0.Q;Q;~%; ; L-H$Y=n#{XP*P*P*z@r:h&M+6;mO3<3<8-9=$#9=$#$#3< O9%Y:z,,X#d=0,t$ZOW j:(*#oG#T,/-';7*y={:7*$+A*%*`+Y:3%a#A;qoj j ^>`OF.hO $8;f, ", +" _,X>$=p+a#A:},7&tO,XM$>:]@Z$)XL;%*;*W*{:s.s.';;O_=#oC>{.F&W z%u-KovXu*6@.:r |$),;oG@I+m%m%m%I+P#d={:E.)XN*M$U%;*$#BO6 G#(*C>#oG#_=_=;O/-;O;O/-6 )$T,;O+&s.,,%,~:a&Z$L;U%c#t>A*A*L.0:L.c+V 1;9%kO=<=<3-+$5=.#.#~: @0.0.~%X+~%X+H$S,S,n#s>s>{Xs>z@r:r:H 6;H y%mO>$co8-8-H ~%L.]>_oQ@f+=<[%V@`-P&m%m%l;v:L>P#),`-7+.:6@@>d=t$ZOp;F&j:(*G#T,T,/-';7*:#{::#_:N,6X,.]@3%WX*.&-j +;^>`OF.-;aO].;= ", +" 6< %>>_o}&tOy+},A:M$r&]@[o)XL;<=goT-7*';s.>+6 _=#oC>V@j:D+ZOu-Ko0,2#@>l.7+`-4O -o=P&I+l;m%l;v: -KoCoP*N,r&M-]@5=8-(.<@)$_=G#_=_=;O)$;O)$;OT,T,)$>+$+P*.#c#Y:%*% N,c#)X)XA*h@h@L.0:c+a&1;1;kO9%=<3-go+,+,.#.#~: @0.Q;Q;~%L-L- OH$Y={X{X{XE.E.E.r:H 6;6;6;mO3d=Kot$ZOW F&V@(*#oT,)$>++&7*{:kX,,9=N,]>L;6X3%a#A;&-7&j Q@`ON*3%[=|@4%G$ ", +" $@!$-:_o!+tO7&+;A:M->:<=[o)XU%io3-@@{:';s.';/-;O_=#o(*j:p;ZOel.*&r |$P#;o;o+XI+l;m%m%P&),0,,,E.K=-;M$#$H$c+U%<=`+F-[o[o[oK=c#)Xt>h@A*L.a&0:a&V 1;9%9%=<+$go+,.#5=.#~: @ @;* @~%; ; L- OS,n#{Xs>z@E.E.r:r:M+M+E.{XQ;9%F->:}&H%]@kOu._=.:G@m%m%l;P&o=;oP#4O`-*&l.u*vXd=t$eT,;O/->+s.<@{:kXBOmO[oio% Y:-;a#!+&-7&y+==`ON*-;: *#Got.P% ", +" P.`$b$s@_o}&tO&:tO,XM->:]@Z$t>}O]>a&co:#';<@+&>+)$T,G#(*{.D+p;ZOu-Kod=vX6@.:r |$), -P#o=v:' I+m%m%v:`-t$7*mOh@}#a#WX% @3A*A*L.0:0:c+V 1;9%kO=<3-+$+,5=5=.#~:;* @ @0.Q;~%; H$S,H$Y=n#{X{Xs>z@P*s>Y=~%+$K=}#M-==M$Y:.#!=#o6@o=m%m%' ' v:;o),),|$7+*&u*vX2#d=Koe*P% ", +" ^%soR@j-N*_o!+},y+tOA:M-F.}#U%A*}O]>c#M+y=>+{:s.6 T,;OT,#oV@F&W z%e+XP&l;m%' ' +X|$u-6 u.=<]>r&a#>:)X OiX4*mO Oh@`+6X}OZ$[oZ$Z$[oF-F-[oZ$[oN,K=c#A*h@h@L.L.a&a&c+1;9%9%kO+$go+$go.#rXrX;* @0.Q;~%H$H$; H$ OY=Y=Y=S,H$ @goA*6X_oQ@A;r&}O Op:#ou*o=l;l;m%P&+XG@L> -|$7+.:.:6@vXd=0,Koe3%S.V=I@H: ", +" !%|o +=+s@z,}&},y+-%A:. s@#+6 /-T,#o(*{.F&W z%t$0,0,2#u*6@7+r 4O4O;oG@G@P&I+' ' l;+X4Od=_=v&E.)X-;F.s@N*z,A;z,f+]>,.}OF-Z$[oZ$[oZ$Z$F-[oZ$[oN,c#c#t>h@h@h@L.0:c+c+V 9%kO3-+$+$+$5=5=rX;*~:;*Q;X+; ; L-L-; ~% @.#1;N,ioA=}&H%a#}#=2#0,u-e+';7*+&6 ;O_=G#(*{.j:W z%t$t$t$d=@>6@.:r `-4O),P#L>+X+X' l;m%' I+L>.:W <@T-; }OA===-%&:&:&-H%s@#t>A*h@a&0:a&V 1;1;9%=<+$+$go.#~:~: @ @0. @~:~:rX+$c+F-]>WX}&Q@*.M--;a&M+p:;OKo),P&m%l;l;I++Xo=L> -),|$`-*&6@vX2#0,0,t$ZOW j:{.(*#o_=)$/-+&s.{:y=7*';_:+$L;Y:%*<=>:z,!+&-j +;^>. s@3%(XF#&>cO ", +" !%;;q$B&F._oA:},7&+;==. WX-;%*N,F-L;Y:5=, {:)$7*s./-)$;O_=#o(*{.D+p;ZOu-t$d=vXu*u*.:7+r 4O -;oo=v:v:I+m%m%l;' +X -vX#o9<@@ Ot>f+!+^>tO7&&:_#}&_oF.hO]@`+,.% F-[o[oN,c#c#K=t>A*A*A*0:a&a&c+V 9%=<3-3-+$go3-+$kOa&)X% 6X-;z,H%,X*.H%M$,-V s>T-7*p;7+o=' l;m%' P&+XG@;o -),|$`-*&6@u*vX0,t$t$eG#T,)$6 ';<@kX{:+&BO%,K=%*`+Y:ios@M$}&},7&-%==. s@3%*OE== T. ", +" !%^,Y...s@A=A:},y+y+qoH%a#f+6XF-N,U%Y:0:6;BO6 <@<@+&6 )$T,G##oV@j:W z%ZOt$d=d=@>u*u*6@7+`-|$ -;oo=o=+XI+l;' m%m%' v:4O2#C>kXA#mOQ;N,F.==},},j y++;},^>}&M$q>>:-;,-]>6X`+}O% F-[o[o[oN,[oZ$F-% % L;6Xio-;s@_o*.,XQ@A:*.,X`O3%A*H$$#(.>+D+6@L>' l;m%l;' P&G@G@o=),|$`-`-*&6@@>d=d=0,t$eG#_=)$/->+s.7*:#7*+&$Os>Z$,.%*6X,-N*. Q@-%7&-%Q@M->:3%9O<>Q.<% ", +" s#nXj,b;>:WX!+},7&7&&-!+M$>:ioU%c#U%,.}O @b@s.';<@s.>+/-;OT,_=C>j:D+p;ZOu-u-0,vX2#vXu*.:r |$`- -P#P#G@P&v:I+l;m%m%m%' +X;o`-t$C>y=H,y%Q;c+Y:s@A;&--%-%+;+;+;tOtO},_#==A:!+H%`O`O. A;A;!+A:Q@Q@Q@,X,X,XA:^>==A;N*,.={:{.@>4Ov:I+' m%m%l;P&P&G@;oP#P#4O4Or *&.:u*vXvX0,u-u-ZOp;p;F&V@C>G#;O/-6 >++&{:kXs.:#iXkOF-6X,.6X-;a#A;==j 7&tOA:M$r&#<9O*>EXq% ", +" v Z>{%J+r&s@A;qoy+7&},Q@M-q>hO`+N,F-`+]@kOu.Co';<@<@';>+/-;O_=C>V@j:W p;z%ZOu-Ko2#2#vXl.*&7+7+|$4O), -o=o=v:P&P&m%m%m%m%l;I+v:;o`-0,C>s.e;!=$#s>Q;9%U%3%q>M-*.Q@qotO-%j +;-%-%},tO},^>==,X!+z,b 6Xt>+,L-r:iXH,9<+&F&vX),G@P&' m%m%m%' P&v:+Xo=;o -),4O`-*&7+.:u*2#2#0,Kot$ZOp;W F&{.C>G#T,;O/-+&';<@7*<@7*BOmO% }O<=`+]>>:z,}&_#j 7&&-A:z,b ,-9O(+0-q-8# ", +" O>)=b; o)+A;==-%7&+;==H%WX-;6X}ON,L;<=)XE.U s.';<@s.>+)$;OT,G##oV@F&F&p;p;ZOt$Kod=2#vX6@l..:r `-`-),;oL>L>o=+Xv:P&l;l;m%m%m%' I++Xo= -4O*&t$V@>+5$W*Q$);_:co6;z@ O~%~:~:~: @X+n#E.mO%,iX);!=V+:#6 D+vX7+4OL>G@I+' m%m%m%l;P&P&P&G@o=;o;oP#|$`-|$*&l.6@vXvX2#d=KoeG#G#T,)$/->+s.kX{:s.y=A# O}OY:%*]@}#F.. }&},y++;^>!+z,3%]>9O[ ]#uo8# ", +" @%:O5*.XN*. }&},y+j _#A;A=F.ioU%K=}O%*U%+$H,:#kX7*<@+&6 )$T,_=C>C>V@j:F&p;z%ZOu-Ko0,KovX@>u*.:*&7+|$),), -;oL>G@+X+X+XI+l;' m%m%m%m%' l;P&L>L>P#),|$`-r *&u*d=u-z%F&{.{.F&p;u-d=6@7+r 7+),;o;oo=I+' l;m%m%m%m%' I+v:P&+Xo=o=;oP#P#4O),`-*&.:6@@>@>2#d=Kot$u-z%p;W j:(*C>C>G#T,;O6 ';s.7*:#:#:#kX3bO)#v ", +" T+$&7.R*>:_o*.qoy+7&},A:M-N*-;6XZ$Z$%*%*h@; V+7*{:';+&+&>+)$;O_=C>V@V@F&F&p;z%ZOt$t$0,d=2#vX@>.:*&7+r `-|$4O), -;oL>G@P&P&v:P&' l;' l;m%m%m%m%m%m%l;l;I+I+P&P&P&v:+X+XP&+XP&I+I+' l;l;m%m%m%m%l;' l;m%' P&P&v:+Xo=;oP# - -4O|$r 7+*&.:l.6@2#2#d=0,Kou-z%z%W j:V@V@(*T,T,T,/->++&<@{:kXy=<@Q$Q;[o`+%*`+}#F._o*.^>j 7&},}&M$s@hO%*d-S g# ", +" n;H-++F>F.a#H%^>+;7&-%,X. A=r&<=L;N,[o6XF-=<3<,,<@{:<@';6 /-/-T,G##o(*V@{.F&p;ZOz%u-u-0,d=d=vXu*6@6@l.7+r `-4O), - -;oL>;oo=G@+X+XP&I+I+I+I+' ' l;' ' ' ' ' ' ' l;l;l;l;' ' I+' ' ' I+P&I+I++XG@+X+XG@L>L>P#P# -4O4O`-7+r .:.:6@u*@>2#d=d=Kou-u-ZOZOW F&V@V@C>#o_=/-/-/-+&s.7*kX:#7*CoY=V ,.Y:L;6XhON*M-!+_#y+j &-!+z,>:#go$O';<@kXs.>+>+/-/-;OG#G#(*V@j:D+D+W z%p;eG@v:+X+X+Xv:+Xv:v:P&P&P&v:P&v:G@G@G@v:v:G@G@L>;oL>L>P#;oP#P#),),),7+`-r 7+.:6@l.vXu*0,0,Kot$u-ZOeG#_=)$/-/->++&{:,,y=';<@6; @[o%*,.`+iof+a#*.Q@-%j -%==*.A=f+,-0%M>r=5# ", +" M#gXc-o&R*N*M-!+_#y+&:-%Q@`Oa#r&io,.% N,,.Y:9%H$(.;O+&kX<@';>+/-;O;O_=#o#o{.F&F&D+W z%e6@.:7+*&.:r `-`-|$4O),4O -;oP#;oP#;oP#L>o=L>o=o=o=o=o=L>o=L>L>L>P#P#;oP#P#),),4O|$|$`-|$`-7+*&.:*&l.u*@>vX2#d=d=t$Kou-u-ZOz%W D+F&V@#o#oC>T,)$)$6 >+s.7*:#y=>++&T-~%t>`+L;,.<=3%N*M$!+&-7&j },A:. N*#<<=/>e>Y$U@ ", +" P%D%g:q *,g=z,A;^>-%7&y+qo}&M-s@hO6X}O% K=6X}O+,y%U ;O+&kX7*+&6 /-)$T,_=#o#o(*{.F&W D+W ZOeu*u*l.l.*&r r *&r `-`-`-`-`-),), - -),),),4O),4O),4O),),),),4O`-`-`-`-`-7+7+7+7+*&.:.:u*@>vXvX2#d=d=0,t$Kou-eG#G#_=;O)$/->+';{::#:#6 )$x>{XkO`+,.`+Y:iof+z,A;==+;7&+;&-}&M$>:#<]+|;e&%@K& ", +" ` ,o=$w$7,s@M$}&&-j 7&-%Q@H%z,F.hO%*Z$}O[o6XF- @3(*V@V@j:W W p;eu*@>u*l..:.:*&.:*&r r r r r r r 7+r r 7+r 7+r r r 7+.:.:.:l.l.l.u*6@6@vXvX@>2#0,0,0,t$u-u-u-ZOZOW W F&V@{.V@C>#o_=T,;O6 6 >+';7*kXkX/-s.Q$E.go,.%*%*%*<=b WXM-}&},y+j tO,X`Oa#b #<1XP>+@p@ ", +" cX],rO7<+>@+z,H%==-%y++;},A:. WX>:hO,.F-U%}O,.U% @%,!=<@6 <@7*s.';>+)$T,T,_=G##o(*(*V@{.F&W W ZOZOe6@6@6@6@6@u*6@6@u*6@u*6@u*6@6@6@6@6@u*@>vX2#2#@>d=0,2#Kot$Kot$e+s.s.{:y=7*6 y=, H kO%*`+,.6X<=-;s@M$*.^>+;j +;qo!+M$>:hO]@o,@O:-hX ", +" P%2,Q&KX6:%=N*_o*.^>-%y+-%qo}&. a#r&}#,.[oU%L;U%%*+,%,H,,,+&s.7*7*+&+&6 )$)$T,T,_=G#C>C>V@j:D+D+W W p;z%ZOZOu-u-u-t$Kot$t$0,d=d=2#d=d=d=0,d=d=d=0,d=d=d=d=d=d=d=d=vX2#d=d=t$t$KoKoKou-u-eG##o_=T,T,)$6 +&>+s.7*7*kX<@<@d%T-M+L.Y:,.%*6X]@#8# ", +" s# #@-I,E* $a#`O,X&-y+y+tOqo}&. WXf+io,.Z$}O,.Z$%*a&>$x>d%s.<@7*7*<@';+&>+/-)$;O_=_=G#C>C>(*(*{.j:j:j:W W W z%ZOz%ZOe_=_=;O)$;O6 >+';';s.{:{:{:<@kXU T-n#Z$Y:,.<=Y:Y:3%N*_oA;Q@},y+y+-%^>!+z,r&#<6XaX(=h#F=8# ", +" 8#_XpXE#1%:*>:z,H%Q@&-7&7&},==!+M-a#r&}#%*[oZ$6XF-,.)XM+W*V+y=7*<@s.7*s.';>+6 6 /-)$;O_=_=_=#o#oC>V@V@{.F&j:F&D+W W W p;z%W W z%ZOz%ZOZOZOz%z%ZOZOZOz%z%z%p;p;p;W D+W p;F&{.j:F&{.V@V@C>#o#o#o_=T,T,;O;O/-6 >++&';s.7*7*kX:#:#d%(.Q$L-U%`+,.]@`+]@hO>:z,A;,X_#-%7&-%qo!+M-N*3%eoD>X%2-z:Mo ", +" P%8#4$ ,A@e=[$6>_o*.==tO7&j &-^>A:. WXf+}#%*Z$[o%*}OF-U%c+_:9+/-/-;O)$;OT,_=G##oG#(*(*(*C>V@j:j:{.{.W D+F&j:D+D+D+D+D+D+F&F&D+D+F&F&F&D+F&D+j:{.j:V@(*(*(*(*C>#oG##o_=T,T,)$)$T,/-6 +&+&';<@7*kXy=:#w-e;(.r:c#,.F-`+]@%*]@-;F.z,A;Q@qo-%&:+;qoA:. a#r&T#b,FOJ*}%K@8# ", +" v ^:C,# 9O>>WX. }&==},&:y+},==}&. q>r&#<<=U%[oU%Y:L;c#N,=<@@w-,,y=:#kX{:s.s.s.+&>+6 6 6 ;O)$;OT,T,T,_=G##oG#C>(*(*(*(*(*(*(*(*(*V@(*V@(*C>(*C>#oC>(*C>(*(*#oG#G#G#_=T,T,;O;O;O)$/-6 6 >++&+&s.7*kXkXkXy=:#CoCov&mOh@[oN,,.6X,.,.io-;N*z,H%,Xqo+;&:+;_#A:H%_oF.,-[#5,f;!OM:v% ", +" P%$:G=r><tO7&y+},,X*.. a#F.hO]@`+F-N,U%Y:% h@A*rX, 7*7*:#kX{:<@<@s.';s.+&>+>+6 /-6 )$)$T,)$;OT,_=_=_=_=T,T,_=G##oG#G#G#G##oG#G#_=;O;O_=_=_=_=;O)$T,T,)$6 )$)$>+>+>+';<@s.7*7*{:kX:#:#kX:#w-8-c+c#t>L;Y:}OL;6X,-r&q>_oA;A:^>+;&:j },Q@*.z,F.3%X;N:#,G>Q>X G$ ", +" $ i=#-':Po7:[$q&A=`OA:qo-%y+y+},==}&H%A=F.b }#Y:`+}O[oL;Y:Z$c+V goH (.{:s.7*{:7*<@<@<@<@';s.+&>+>+>+/-)$)$/-)$/-/-;O;OT,T,T,T,T,;OT,T,T,T,T,T,;O)$/-)$/-/-/-6 >+6 >+s.';s.7*7*<@<@kX{:{:<@7*,,H,n#1;c+L.}O<=,.,.]@]>3%>:q>M-*.Q@&-j 7&+;&-==*.M-q>b {**oI:C&F$TOcX$ ", +" 8#2o1>lo_OX:=@A.z,`O}&qo-%y+7&-%qo==A;M$a#>:3%]>Y:,.% [o`+<=,.t>=<+$+,E.oo:#s.<@7*7*7*<@';<@7*s.s.';<@<@s.>+';6 6 >++&+&+&+&>++&>++&+&+&+&>+>++&<@<@s.s.<@<@<@<@<@{:7*kXkX7*<@7*Co[%S,3-+,3-K=6X]@L;U%]@]>,-f+N*_o. }&==tOy+y+-%},Q@H%M-q>-;J#{=t&5+nOy.uo ", +" G$5#Z,6#.+aX=@A.q>M$!+^>tO-%j 7&tO^>}&`Oz,N*>:3%]@%*%*,.F-Z$`+]>]@c#5=rX;*z@$+e;:#<@<@<@7*<@7*{:7*kX<@s.<@s.';<@<@<@<@<@<@<@s.<@<@<@s.<@s.s.{:{:7*7*{:{:{:<@<@7*{:kXV+4*S,rX~:kO[o,-]@`+,.`+]@<=,-b s@a#. *.Q@_#y+7&+;-%_#,XA;A=s@b o-Q-m+L+ :E@y,$ ", +" T+l&j#r%h;sO-+y#WXM$H%A:&-+;y+j +;},==*.H%M$WX>:hO<=`+,.L;L;}OZ$U%}#,-F-3-~%H$ OL-P*>$$OU ,,{:7*s.{:7*7*<@{:<@{:7*7*{:7*<@kX{:7*<@7*7*<@<@{:{:{:Cov&[%y%n#H$S,H$0.kOL;#<]>,.% `+%*]@}#,-f+s@z,. *.A:_#-%j j j tO==!+M-A=F.yOX;{+*,c-%j j j +;tO==}&A;M$A=N*f+#<<=`+L;`+Y:L;% U%%*<=}##<6XK=+,; n#s>P*P*E.M+y%8-%,4*[%$OooW*x>A#T-);$#>$8-y%h&E.z@s>s>{X~%kO[o<=#<}#]>Y:L;L;6X6X<=<=]>#<>:WXM$H%!+,X_#-%y+y+j -%_#,X`O_oq>r&yO}#g+ %+*> dM$A;A:_#-%y++;+;+;&-^>,X!+`Oz,WXs@r&hOio]@`+,.%*%*%*%*,.% U%6X]>}#hO#]>}#3%>:q>_oM-*.}&Q@_#-%+;+;j j },Q@*.. A=F.3%#a#M-*.,Xqo-%7&j +;-%},_#==}&A;`O_oWXq>s@f+#<}#<=%*,.U%L;`+%*`+`+`+Y:`+`+}OF-F-% L;`+,.`+`+U%F-% }OU%,.%*Y:`+`+Y:Y:Y:6X%*6Xio#H-_-5; ", +" MXk,#+;:f&R>b#hO>:N*z,. !+A:^>tOy+7&y+-%tO},&-^>A:*.`O. _oz,q>F.F.r&3%}#}#]@]@Y:%*L;`+,.U%U%L;}OL;%*`+,.L;U%U%,.,.%*6XY:]@io}#}#3%r&s@q>a#z,M$. A;}&==_#},},tO+;y+7&-%_#,X}&H%_oWXr&3%,-]@7:E ]:~.P:ROi= ", +" 2>k=~X$,X%l,0%b F.N*_oM-A;A:==&-tOy+7&7&y+-%},_#qoQ@A:*.A;`OM-_oA=WXN*s@s@s@>:r&f+b f+-;-;3%3%hO3%-;f+b r&r&>:s@s@q>a#a#z,M$M-H%*.!+Q@^>_#&--%+;y+7&7&+;&-qo,X!+`Oz,q>>:b 3%*%M*DXj%VOs+5-6% ", +" 6+'.xX/,y;(X_#tO-%y+7&y+y++;tO&-_#qo^>==,X}&!+A;A;H%`OM-M-M$_oM$_o_oM-M$M$M-M-`OH%H%H%*.!+A:Q@==^>qo_#},-%j j &:7&j tO},^>Q@A:A;. A=N*f+-;#.,u ", +" l-@*1o5ObOGOD>.qo_#},-%j 7&&:&:7&y++;-%-%},},},_#_#_#&-_#qoqoqo_#_#_#qo_#_#},},},-%-%+;j j 7&&:7&j +;-%&-_#^>Q@!+H%M$a#q>F.r&3%}#W=(X/>t*0@2;).;+8# ", +" P%v%x*QX8>B%H=a;_%s=p&i*-;r&s@WXz,M-`OA;!+Q@^>_#_#_#},-%-%+;j y+7&y+7&&:&:7&C.7&7&7&7&&:&:7&&:7&7&j j +;tOtO&-&-_#^>Q@A:!+A;M-z,a#s@>:f+hO}#0%1:s@WXWXz,_o`OH%A;}&A:A:==^>^>_#qo_#&-_#&-_#_#_#_#&-_#_#&-qo^>^>,X!+!+!+A;. M$A=a#N*>:F.f+3%,-}#<#3>i@n,H;G;0#W#%%H#$-^#!% ", +" ` x&Y@:;L&.$U:*N*A=a#A=_o_o_oM-M-M-M-M-M$M-M-M$_oM$A=a#A=WXN*q>F.F.>:f+hO#<3%B.`;{==O0;y*1:P>!>#@-$}=HOi= ", +" ^#U-~;d+=oP$]$~-v#[>G,W@#*iohOyO-;hOhO3%-;-;-;b b -;b f+b f+f+b b b -;hOhOhO#<#<3%#<#:XV%%*C=k*]$]Xo>=%],x#x#!%v ", +" !%2o3=D:0o9>B+f zo)o-*O$7#]@Y:Y:Y:%*%*`+`+`+Y:<=io]>6X%*`+%*%*%*Y:%*%*Y:`%C;u;:@g$x:T$b.4:5#3=Z;Z&Y 8# ", +" G$f>=>k#D:m>'%H>q;{&f->@C#k+~>m;;,^Oz-R:h%XXi l#R;Bo{&+<4=k%|#X@{Od.r@8# ", +" $ $ $ $ 2&;.Q::+m,Z#d:j;x$G=Y.3;>Xn:@-0&8@8=2<>;%:C$f<} l*I $ $ $ P% ", +" ", +" ", +" " +}; diff --git a/share/pixmaps/bitcoin32.png b/share/pixmaps/bitcoin32.png new file mode 100644 index 0000000000000000000000000000000000000000..be7c119759e931f5c613ecb6ca8e39b211e5f7e0 GIT binary patch literal 2203 zcmV;M2xRw(P)IAT5ZFNv8{eXcl6~pDd-qKmfyLaEJcP~GG{`_?z{v7~;A3b{1rL?s4a|M6D zW5tsG&cgw7k50 z$(1Wt*3X5?u zTMdkb5R8O^XjVvI3Dleb>UAe$%Lu1xMJol0he{ap%+V1r1^qjB?zG@M!^fI6YYZqL z=FXjqW|E|d&v=hE4>5eyI(-TY3qPDVaiR$hMh+i7?7DR6VvaRf%poU~;|$6H)Vg(R zdtO#n_Q!Bh7on~G{rfvH>W&^gYC`4zgb5RzVlAnzuI@onA<&DOOwk-OY}hcP`plU# z<`7D$Ge|*v=gu8-gs=d~HTLL(=LF_HNg&|)^XI#%Q>Qw$ve{@-y7csP+PI@)ya(_= z^actxYv|CSHee8kC~6*^WX&%DXg`EWU^)OB7`SlZg0X@K)oKRHmxz)ven~1mKHh|x zl$1odGIX64NCW*uYYIIKQgwo<81)jE0DkP&*Vo(2IF5>nvTP}d#A{ho0vLsU5@Ak| zd2w+u?QP{?kfAF98mjJz4}|_LT||MLKv0i!km8I?a7+jA+qZ9D1Ar~^5I zr=JsNnVFex!-fsU5aN}K%kA9lNp&n zI~n)x-P?jfGZ|4wg5ZeR4>+G8*VxLZjd22djleKnqIvNtl5+Lfv13K*)sbVy zjIr^ndoDRS*_;uKAj}Cef)!8c;>C*%9H*z+&j56@a^=cqVKbx{NX!G~f)YF>oAQu0 zp$(d1+qD5P#2g@HxdlBfMNsBbeEG5o2j^r6h*!JE{{jpFA31WwrKP1gHa2t% zKG6f^)%%rVITw)zs8$!(Rmbo5?Ah}L+bD!Mdh}?wdi81(3?f^$Y?-wa+3?(V0|5cV zwVw~zvG7cpGR2r=0m27e!`MzuP5n+KsN$W#*J$L(kzc6{Z)^862;o8bs#UAp+O=yf zTl4{)v?fCI)Z-Yc{Q#m>=?0!tQZ}i)&q9`)n@d>>1z;Wa01uxuX_ARc6h6_*g`#MI zGKruR0D%cq%{8l>|7d|3)X&<%o&g&_cG=*-1ZzK_SQEBv*}{CO)6QstGkUfrQWn`r(?=tI)OI*FzY+b96AcjWZl!CYW&kU5mozOcsZpfr5qQFCY){rAP> z5;2(j*KdO`X1pIDP|2X6&T5x2`Y>51Fsam$QXp7rOqPD|_)hRkHj1a-Fa%S|wm@H0 zAFDHt!W6TBO>Xn9_@BOvU_wgIR~tTc`0{M~OV>|MhM7a&J(pl6#o!F4{AT0jYFDdZCpFIV z#M00Df77?=8-JYo0|ydIxoZ2hdixtu+FN29pzBm^-IDaIi3LriD- c #ACACAC", -", c #B2B2B2", -"' c #AAAAAA", -") c #ABABAB", -"! c #A6A6A6", -"~ c #A3A3A3", -"{ c #A8A7A7", -"] c #A5A5A5", -"^ c #ADADAD", -"/ c #9E9E9E", -"( c #ADACAC", -"_ c #A2A2A2", -": c #A0A0A0", -"< c #9D9D9D", -"[ c #A5A4A4", -"} c #9C9C9C", -"| c #9B9B9B", -"1 c #979797", -"2 c #8C8C8C", -"3 c #848484", -"4 c #838383", -"5 c #878787", -"6 c #929292", -"7 c #9A9A9A", -"8 c #AFAFAF", -"9 c #8B8B8B", -"0 c #7F7F7F", -"a c #808080", -"b c #7E7E7E", -"c c #828282", -"d c #969696", -"e c #939292", -"f c #999999", -"g c #898989", -"h c #8A8A8A", -"i c #888888", -"j c #959595", -"k c #939393", -"l c #909090", -"m c #8D8D8D", -"n c #9D9C9C", -"o c #B4B4B4", -"p c #B6B6B6", -"q c #919090", -"r c #A9A8A8", -"s c #B8B8B8", -"t c #BCBCBC", -"u c #B5B5B5", -"v c #C5C5C5", -"w c #C1C1C1", -"x c #B3B3B3", -"y c #C8C8C8", -"z c #BFBFBF", -"A c #B9B9B9", -"B c #AAA9A9", -"C c #9E9D9D", -"D c #949494", -"E c #919191", -"F c #8E8E8E", -"G c #858585", -"H c #B7B7B7", -"I c #818181", -"J c #989898", -"K c #949393", -"L c #989797", -" ", -" .+@ ", -" #$%&*==*&-; ", -" +>,')'!;~!%%)={ ", -" -*)&'!;+##+~]%^%*/ ", -" ()&'$;_:/<'[ ", -" ^%'!~+#/<}|||}/#+~!%-] ", -" '));_:/<}1234567<<#+~'%# ", -" _&8$_/<}}790aabcd<}&e ", -" *,);:/}% ", -" ]88$_/}<#+fkllmi47_:<}<+!^8j ", -" ^,);:<}<+;}7djkmh;!_/}<#~%>~ ", -" no8$_/<<#_]#:}|fk18';#<}/+!^= ", -" %^);:<}<:]]_]~_:}$p^!+/}<#~%=q ", -" r%$_#<<#_-!!%''%]st,';:/}/+]$# ", -" ;-;:<}<:;)!'^8,u&vwp&$+/}<#~~+ ", -" ]']+/}<:;-~-*=xuxyzu^]+/}<:~]+ ", -" ;>-~#<]+<}<:}f'=*)<^s8-~#<}<:;%)C ", -" !=*%~#<}/dD8=8+jEF2i9d}}/_$&u ", -" ou>]+<}|kD,**#|1DlmG57<:;'x* ", -" BH*%~#<7k<=*8&>%;+/gI7/+$^8+ ", -" :xu>]+<}1-=*8&^%]_:a4|#;',x9 ", -" (p*-~#/<~~_+_+#]~+:/}fJJfJ1dk6}_;'== ", -" +&=>-]_+#/<<<<<#:_;$)8&K ", -" [&u*^-]~+#<%]~+:_;$)8oo=L ", -" L*,Au*>-]]$)&oH,>2 ", -" #*p,o=^)8,8p)f ", -" D:]^=*>_#m ", -" "}; +static char *graphic[] = { +/* width height num_colors chars_per_pixel */ +"32 32 309 2", +/* colors */ +" c None", +". c #444444", +"X c #474747", +"o c #666666", +"O c #888888", +"+ c None", +"@ c #AAAAAA", +"# c None", +"$ c #CCCCCC", +"% c #474747", +"& c #EEEEEE", +"* c #535353", +"= c None", +"- c #757575", +"; c #979797", +": c #B9B9B9", +"> c #DBDBDB", +", c #FDFDFD", +"< c #626262", +"1 c #848484", +"2 c #A6A6A6", +"3 c #C8C8C8", +"4 c #EAEAEA", +"5 c #686868", +"6 c #737373", +"7 c #717171", +"8 c #939393", +"9 c #B5B5B5", +"0 c #D7D7D7", +"q c #F9F9F9", +"w c #3C3C3C", +"e c #5E5E5E", +"r c #808080", +"t c #4E4E4E", +"y c None", +"u c #A2A2A2", +"i c None", +"p c #C4C4C4", +"a c #E6E6E6", +"s c #4B4B4B", +"d c None", +"f c None", +"g c #6D6D6D", +"h c #8F8F8F", +"j c #B1B1B1", +"k c #D3D3D3", +"l c #F5F5F5", +"z c None", +"x c None", +"c c #434343", +"v c None", +"b c #5A5A5A", +"n c None", +"m c #7C7C7C", +"M c None", +"N c #9E9E9E", +"B c #C0C0C0", +"V c None", +"C c #E2E2E2", +"Z c None", +"A c #5C5C5C", +"S c #474747", +"D c None", +"F c #696969", +"G c #8B8B8B", +"H c None", +"J c #ADADAD", +"K c #CFCFCF", +"L c #4A4A4A", +"P c #F1F1F1", +"I c None", +"U c #565656", +"Y c #787878", +"T c #9A9A9A", +"R c #BCBCBC", +"E c #3F3F3F", +"W c #DEDEDE", +"Q c #6F6F6F", +"! c None", +"~ c #434343", +"^ c #656565", +"/ c None", +"( c #878787", +") c #A9A9A9", +"_ c #CBCBCB", +"` c #EDEDED", +"' c None", +"] c #525252", +"[ c None", +"{ c None", +"} c #747474", +"| c #6B6B6B", +" . c #969696", +".. c #B8B8B8", +"X. c None", +"o. c #DADADA", +"O. c #515151", +"+. c None", +"@. c #FCFCFC", +"#. c None", +"$. c #3F3F3F", +"%. c #464646", +"&. c #616161", +"*. c #838383", +"=. c #A5A5A5", +"-. c #C7C7C7", +";. c #3B3B3B", +":. c None", +">. c #E9E9E9", +",. c #464646", +"<. c None", +"1. c #3B3B3B", +"2. c None", +"3. c #4E4E4E", +"4. c #707070", +"5. c #929292", +"6. c #676767", +"7. c #B4B4B4", +"8. c #424242", +"9. c #D6D6D6", +"0. c #F8F8F8", +"q. c #3B3B3B", +"w. c None", +"e. c None", +"r. c #5D5D5D", +"t. c None", +"y. c #7F7F7F", +"u. c None", +"i. c #A1A1A1", +"p. c #C3C3C3", +"a. c #E5E5E5", +"s. c None", +"d. c None", +"f. c None", +"g. c #373737", +"h. c None", +"j. c #4D4D4D", +"k. c #4A4A4A", +"l. c #6C6C6C", +"z. c #8E8E8E", +"x. c #424242", +"c. c None", +"v. c #B0B0B0", +"b. c #4D4D4D", +"n. c #D2D2D2", +"m. c None", +"M. c #F4F4F4", +"N. c #424242", +"B. c None", +"V. c #4D4D4D", +"C. c None", +"Z. c #7B7B7B", +"A. c #9D9D9D", +"S. c None", +"D. c #BFBFBF", +"F. c #E1E1E1", +"G. c None", +"H. c #636363", +"J. c None", +"K. c #424242", +"L. c #464646", +"P. c None", +"I. c None", +"U. c #686868", +"Y. c #8A8A8A", +"T. c #424242", +"R. c None", +"E. c #ACACAC", +"W. c #CECECE", +"Q. c None", +"!. c #424242", +"~. c #F0F0F0", +"^. c #555555", +"/. c #777777", +"(. c None", +"). c #999999", +"_. c None", +"`. c #BBBBBB", +"'. c #DDDDDD", +"]. c None", +"[. c #FFFFFF", +"{. c #424242", +"}. c None", +"|. c #868686", +" X c #A8A8A8", +".X c #CACACA", +"XX c #3E3E3E", +"oX c #ECECEC", +"OX c #454545", +"+X c #515151", +"@X c #737373", +"#X c #959595", +"$X c #B7B7B7", +"%X c #D9D9D9", +"&X c #454545", +"*X c #FBFBFB", +"=X c None", +"-X c None", +";X c #454545", +":X c #606060", +">X c #A4A4A4", +",X c #3A3A3A", +"o c #484848", +",o c #6A6A6A", +"X&o+XE uX+. ", +" m.;X* _X3 C P 0.*X[X[X@.0.& roXoh 6X8.v ", +" { ^XPX=oa.eXM.%X..u 8 8XwokX0 6oxXC VXg XX/ ", +" d ~ G 9.~.eX.6owX|Xg.s. ", +" I.,.- wXl ro; @ 2o=.mXm _ Xo-.K r =.XoyXg g a.P 4o,o%.KX ", +" bX+XB ~.oo*oeo9 2 GX@XkX$ p -.W (Xy.Y g 7Xr.F 4 4 YXS 1X ", +" <.DX8 pX$oGX..2o.o XJ gX_ !X$ k W.] Z.0o7 g r N j xXW O MXu. ", +" 'XLXX@ ).} W W.#opXGXU y.&o_X..9.a D.n.JXB >ow. ", +"h.b.y.rol 8X8XwoN yXQXZ.8 a ]XTX~.*.7 ) =ok 9.]XCX0 2 P o.(Xt d.", +"IX7o=.& o.&o#XUX.oE.7.7XYXooC oo>.L.F =.HXlX#o-.=.m :XW 2X).T._.", +"M s eoeX: O v.eoB eo@ogX'.>.~X6opX=.: /.3 @o5.PX,o,o9o..6o9X. Z ", +"Q.9o!X$o..3 k .XXop .} $oJXM.0.[.[.).l.z.Z./.PX7XF gXGXl B dX+ ", +"Q tXW.M...wXwX.X7.Y +Xv.[.q , [.kX< tX|XWXr 0oPX( kXW.: ~.-.* 6.", +"qo%oHXM.: $ 7..o} &ooX[.RX, RXJX* &o_XoJ.", +"! >o`.$o`.r _X_XFXEX,oRXxX~.*X_X&.8X8 yX) J @oeo$XUXEX: P j {.# ", +"e.!.i.oXTXy.i.`X.X( QX*XoX>.$o|X%o4.(X@X} /.PX%oF F }Xrooo .AXy ", +"= j.mX'.6oGX0 0 #oy.HXJXa -oa.oo-oroW TXo.]XF.tXo ^ O $o0 l.O.}.", +" 2.3.iX6o4oeoC iXY & 4 oopXCXW TX]X9.k 4olX$ dXy.Z.K & `.. f ", +" X.K. r c z ", +" 6 dX`.~X4 F U dX$.k.}Xg g F SX^ :Xb e F mXB @o>.a 7.{.#. ", +" =X&XgXK 6oa 7 (XJ 3 4o!XiXVX@ou UXN J eo$X2 pX4 _ e V.n ", +" o3Xy.wX~.~X@op 0 wXW.YXwo( |.5.A.*o .@ 4 ~X4o@X;.I ", +" G.w y.4o~Xl K @o Xr < EXOo/.&o*.NX4oxXa _ @X3of. ", +" aX,XU.: CX~.6oo.7.*o .T XD.W xX& TX7.e DXcX ", +" i OX>o( D.> 4 xX0.0.eX$oP 2X%X`.r . L 5X ", +" S.[ N.dX4.UX9X=o-.-.B j #Xl.L.x.' C. ", +" (.BXrXK.~ >o/X/X>o~ ZX0X{Xx ", +" zXqXt.)X| w.-X1o " +}; diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png new file mode 100644 index 0000000000000000000000000000000000000000..d224bfc8b66a901eb6ab16aee4f161d81641fb8b GIT binary patch literal 5922 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 c #474747", +", c #4A4A4A", +"< c None", +"1 c #404040", +"2 c #434343", +"3 c #404040", +"4 c None", +"5 c None", +"6 c None", +"7 c #535353", +"8 c #404040", +"9 c #404040", +"0 c #757575", +"q c #404040", +"w c #979797", +"e c #B9B9B9", +"r c #404040", +"t c None", +"y c #DBDBDB", +"u c #404040", +"i c None", +"p c #404040", +"a c #FDFDFD", +"s c #404040", +"d c #474747", +"f c #4A4A4A", +"g c #404040", +"h c #626262", +"j c #848484", +"k c None", +"l c #515151", +"z c None", +"x c #A6A6A6", +"c c #C8C8C8", +"v c None", +"b c None", +"n c #EAEAEA", +"m c #515151", +"M c None", +"N c #4F4F4F", +"B c #434343", +"V c None", +"C c None", +"Z c #717171", +"A c None", +"S c #939393", +"D c None", +"F c #B5B5B5", +"G c #4A4A4A", +"H c #474747", +"J c #D7D7D7", +"K c #434343", +"L c #525252", +"P c #474747", +"I c #F9F9F9", +"U c None", +"Y c #3C3C3C", +"T c #5E5E5E", +"R c #808080", +"E c #4D4D4D", +"W c #555555", +"Q c None", +"! c #A2A2A2", +"~ c None", +"^ c #525252", +"/ c #C4C4C4", +"( c None", +") c #E6E6E6", +"_ c None", +"` c None", +"' c None", +"] c None", +"[ c #4B4B4B", +"{ c #4D4D4D", +"} c #6D6D6D", +"| c #8F8F8F", +" . c #464646", +".. c None", +"X. c None", +"o. c #B1B1B1", +"O. c None", +"+. c #D3D3D3", +"@. c #F5F5F5", +"#. c None", +"$. c None", +"%. c None", +"&. c None", +"*. c #383838", +"=. c #434343", +"-. c #5A5A5A", +";. c #434343", +":. c #7C7C7C", +">. c None", +",. c None", +"<. c #9E9E9E", +"1. c #464646", +"2. c #515151", +"3. c #4E4E4E", +"4. c #C0C0C0", +"5. c None", +"6. c #E2E2E2", +"7. c #474747", +"8. c #3F3F3F", +"9. c #474747", +"0. c #464646", +"q. c #474747", +"w. c #696969", +"e. c None", +"r. c #4A4A4A", +"t. c None", +"y. c None", +"u. c #464646", +"i. c #8B8B8B", +"p. c None", +"a. c #ADADAD", +"s. c None", +"d. c #CFCFCF", +"f. c #494949", +"g. c #464646", +"h. c #515151", +"j. c #F1F1F1", +"k. c None", +"l. c #434343", +"z. c None", +"x. c #515151", +"c. c None", +"v. c #343434", +"b. c #565656", +"n. c #787878", +"m. c None", +"M. c None", +"N. c #9A9A9A", +"B. c #4A4A4A", +"V. c #434343", +"C. c #BCBCBC", +"Z. c #3F3F3F", +"A. c #DEDEDE", +"S. c #3F3F3F", +"D. c #434343", +"F. c #3F3F3F", +"G. c None", +"H. c #4D4D4D", +"J. c #434343", +"K. c None", +"L. c #3F3F3F", +"P. c None", +"I. c #434343", +"U. c #3F3F3F", +"Y. c #656565", +"T. c None", +"R. c #3F3F3F", +"E. c #878787", +"W. c #424242", +"Q. c None", +"!. c #A9A9A9", +"~. c #464646", +"^. c #CBCBCB", +"/. c #3F3F3F", +"(. c #4D4D4D", +"). c #EDEDED", +"_. c None", +"`. c #464646", +"'. c None", +"]. c #3F3F3F", +"[. c #525252", +"{. c #464646", +"}. c None", +"|. c #747474", +" X c #3F3F3F", +".X c #969696", +"XX c #3F3F3F", +"oX c #4D4D4D", +"OX c #B8B8B8", +"+X c #555555", +"@X c #DADADA", +"#X c #545454", +"$X c #3F3F3F", +"%X c #3F3F3F", +"&X c #FCFCFC", +"*X c None", +"=X c None", +"-X c #464646", +";X c #3F3F3F", +":X c #616161", +">X c #545454", +",X c None", +"o c #DDDDDD", +",o c #424242", +"O c #AFAFAF", +",O c #535353", +"+ c None", +",+ c #4E4E4E", +"<+ c None", +"1+ c #4C4C4C", +"2+ c None", +"3+ c #6E6E6E", +"4+ c None", +"5+ c #909090", +"6+ c None", +"7+ c #B2B2B2", +"8+ c None", +"9+ c #D4D4D4", +"0+ c #F6F6F6", +"q+ c None", +"w+ c #404040", +"e+ c None", +"r+ c #474747", +"t+ c #404040", +"y+ c #444444", +"u+ c #5B5B5B", +"i+ c #444444", +"p+ c #7D7D7D", +"a+ c #4F4F4F", +"s+ c #474747", +"d+ c None", +"f+ c #9F9F9F", +"g+ c #4F4F4F", +"h+ c None", +"j+ c #C1C1C1", +"k+ c #444444", +"l+ c None", +"z+ c #E3E3E3", +"x+ c #474747", +"c+ c #404040", +"v+ c None", +"b+ c #484848", +"n+ c None", +"m+ c #484848", +"M+ c #404040", +"N+ c #6A6A6A", +"B+ c None", +"V+ c #444444", +"C+ c #8C8C8C", +"Z+ c None", +"A+ c #AEAEAE", +"S+ c #525252", +"D+ c None", +"F+ c #D0D0D0", +"G+ c #F2F2F2", +"H+ c #474747", +"J+ c #525252", +"K+ c #353535", +"L+ c #434343", +"P+ c #575757", +"I+ c #797979", +"U+ c #9B9B9B", +"Y+ c #4B4B4B", +"T+ c #BDBDBD", +"R+ c #444444", +"E+ c #DFDFDF", +"W+ c None", +"Q+ c #404040", +"!+ c #444444", +"~+ c None", +"^+ c #404040", +/* pixels */ +" o .loD+4+l+T.t.lXC D+y.>.cX ", +" cXi ,XEoO.{ GO0.~.d Go2XJO# x+=o,+9X_ o+( 9o ", +" AXc.K.SXu.OOO mOD.q.mX1+ToTo1+&OiO1oq L.gX.Ol h+t 4 ", +" >.s.HOr+M+9 )XN 7O:X'XqX|.n.]op+n.hoRo+ @+@o[ J.so*OeXq+UOAX ", +" MXP.RO2 U.uOfo@+} p+| jXa.zoT+QXzXXOQXT+zogOf+-ORXw.-.1+SOF.0.,.@O5 ", +" o >+D L+7o)XP+w.]ow o.XO- +.uX}O@Xy ZOZOy boJ ~oobo9+- T+jXhX0o0XBOgXPoP.oJ F+j+jXI+`o`XR.wXBXAX ", +" Uo1OO+V.7OqX.XT+o~o5XFobOvOp B Q . ", +" Uoz.c+%O0oEOzoO-O*+A+gOroFo|oMOI+1+<.5XHoHo5X5X5X5X!O7+-.DXHooXOQXj+zX/ Ho!O!X&ou+DXWo$+n.0 hoqXRo=O0oYO>Oj.lOz+uX/ -O7Oxo~O'o ", +" AXHO3oP+p+-oJ +Oj.@.eOkoe j+T+'Oa.x Fo!.{X.XUXU+>ozXzX;+5X!OtoF+!XZ fo0 RX8On.bO|.Z Ro} N+YO'XXOKXuoE+GXF 0 mX9OIoMX ", +" B+kO9.N+*+d.E+).0++.w OX;+T+FXWOFoWO= {X!.E.@oT+J Ho5X!O^.jO.oboO5X9+boy +.*+!OKX6X@X^.U+`o%XdOV ", +" 9om.#O7 p+eO}O) KX+Oi.C+N.qO<.f+! *+3XWOroWO| @o*+z+oboy >oA.rO6.).a.q._O.XA+4.c ^.jOd.F+o>oE+!Xz+xXJo: M. ", +"cX[oQ+-.C+to>ouo0+7+RXrX.Xw &oEX3Xa.yX'OyXA+5+b.{X/OrO6.+OxX:+6X).6.P+v.fo} |.*+zX!O^.jO.o- XO{X5+8ORo=O'X@+zo2O) J zXSomX;.4O9o", +"AX#+nOYOEXF+rOXoXo.X$+rXMO! A+OXeOT+-oOXF gO$+UXjOn +O) Jon /O).2OF+u+n.'O!o@+w j+c !O/ yXqOEOn.hoqX3+VXN+@+.Xj.n @XtoS [.1 e.MX", +". , !+w.!.9+6.2O) E.Wo= -o;+5X;+XOQXC.e 'OWOqX} xXn 6X/O).lOXoG+pX).ZO2O +WOu+|oQXe x Wo$+8O#o0 |.Z Ro} =OYOp+6X).>o.of+-.r >X( ", +"fO1.m+qX!ouXxXKX@X`O4.d.F+jO!OHozX4.T+VO'O<.@+DXlOuo).lOj.2O@.(omoa a DOKX$+YOMOMOsO$+]o:.8On.bO|._OqX3+VXpOqXA.XorOF+gO:Xs x.%.", +"<+yo1+|.-o}O) 0+F+*+O`ORo@o[.VX= G+(opX +&Xa DOa moa.(OmXUXVX:.wo$ E.EOOY.KOFO;o", +"fOs+q.3+7+~o+OKXy p+C+S ko.XMOMOE.dXzo) T+4.I +I pX0+@.2OG+KX`ON j w .XrXDX| MOx FXF e -oeOj+/ 5X^..oF+- 'O| rOlOA.d.= @+s }X_.", +"Uo% ,o+ ro+.6.j.:+woE.S `O.Xw w i.Z -O0o*.&o(o(o0+@.2OG+XoXon Ro`o-O`OWorXN.Fo= A+o.yXzoe C.QXXO;+HoQX= -O3+$+6XuoZOjOEXP+q #XHX", +"AXBo8 AoU+d.A.: j.&oR rXS kow MOko$ 0 P+I.4.pXKXG+j.Xo: ).Xo9+foAoO7+yXa.N.So_ON+T &oXoJoboc 5+N zO] 5 ", +"cX.+Z.b.[Xc y n @.F 8O5+S .XEX!.zoT+FXRX+ E+KXj.lO: )./On XoFXK+`Xu+:X0oY.+ pOw.=OVX3+RoZ qXVX=OZ _OqX} w.Ao-oG++O~o4.]oq.)o..9o", +" VotXToI+T+J ) KXuXp+5+*+F / - jO!OF _Oj : Xo: uo/On JoJo2OOXqX|.n.I+I+8O8ORX8ORXRXRX:.RXn.UXKOYOZ Z 3++ Roy lOrO.*X].u+5+toy n @.Hox 9+}O~oGXd.5XU+h tolOJo:+) xXz+6.!XrOrOA.>oZOy @X}OJ uX~o+.GXoZO@Xbo}OuX~o9++.oZOy @Xy xXwomX$ 'O^.>OA+: uoA.F+zo_OiOH d+O0oYOY.dXu+`o@+YO3+R 5+MOMOkoS 5+DXi.sOwoj $+]o8On.:.EODX`O&oWOeO4.f+zXXo/OA.GX4.woN 9 }oD+ ", +" OF+ZO:+G+lO7+N+Z U+T+F+9+ogO! 4.GX+.On.To$X$O O4 ", +" 6+=Xvop b.:.>O^.uXE+:+lOKXn !Ox w j } 0oY.w.} Z bOI+p+hXhXp+8OSof+^./O2Ouo+OZOGX5Xro_O[ $X:Ok.>. ", +" 6OCodo$Xfo_O|o/ GXy 6.6XXoKXlOy e w p+Ro+ Y.Y.'X=O_ORXsOf+T+ZOlOG+).) A.J d.4.N.w.m+$XvXk.^O ", +" 6+& H+gomX0oC+F - 9+y !X:+).G+KXG+n E++.^.;+Ho- 9+rO/OG+2OXo/OxXE+booJ o@XJ +.jO/ !o`OZ 7 I.nOwOe+o+cX ", +" o . WXH.=.Nom+7ORo[X3XOX/ ^.d.GX+.9+~o9+9++.+M X.S+ooi+Oor s g KOKOKOg g s :ol.X+ZXbX4XaO_.vD<%gn=l-+Q0u)c^UPb6?L3@;>uILOfkVycJ)0 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 literal 6702 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 diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp index b5a30408aa453f0133aa1f3962c05f01ad6f660c..791215533127c69d7e61e420e4c1b7c88132d291 100644 GIT binary patch literal 25820 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 crAFDQTU761SM literal 25818 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
z zZ&;VWuS)eXffqdDO6ZcamP`jOa*SsZxEy{afp1uAv8>0LkMoS{0FAPx7CGy{ZL_=m z;cZ6FMYJF($x%8Jni>{u)lwq6W`2^4)k=^N(})D3U^N*9yI6K&R(^1Oy`1Ok-`TtFC9hoeb7Mr|Wsqdm@WC zA0jKoITw4rRD+>Ml262#9PR-O1%0G#6Ax~nV;%R=xRYy@-%tFGGIx=#Pv8_}X`|7V z%II3O+f}Avv!+4A6Z8B4rAaX;?c`^x=vLkBQHtJYlj!?2|l81ljEE}4DGWCvm zNSom+H$rT`6lJMWS(G!GD#^(Njw#2oSPy9O_bVnU%u6I=Vb-drO0+N5gFD0m+sPW< zu^wIf72`JMlXvvvCOW?MHtRi*A^5?Lo@nIeDfqs(sUgpqm61!LC z`nJk@2EYKc(~7ma+zz3U2UjL1f58uKB6X5T9c}EhYmFZMeZnk}hSf2$!Ige*LLAwF ztG8kC9mG+l2!^tbmtoDcM&3_KfNoevxuf4|&rB8w#oDIIB=AApiGYuF$I)*m1G*o5 zM9jDv&{U%wLu}z7qBPz*BATLT71K@yw`-OZ&0#@$SdVRRZ)83i-xIHk8|Z7vRhnUu=#QLb_gPcu=i%fxhM#X_1*7UoAmXJ{feOM3W60)P)Kr9J6reC~B*g47> zA&-{H8D)xQD`>1+^0Ww&iX~4HChdcskBUyzUS#G%Xd2_SSZ`RbpgCk^9cV`{`V}K; zDN&Y?G=LVIeoH}AtU62D{49&w&0zikgcd=V4sL1O9@^k`a-R5Y61!{8^(8m?#7>0> zbYFlsBo=wwGy|Qw4cm!hGS~k=T)K8dnSq(*Cy15g)|;+#8>D;+(`nzz07@Nu1|D=P3%cEb{NFD zb(6l)e24Y*v<@+xnVmGKn)6AZ_pDLQfR?m@hPY#_O>;oQ9cXf1LB~2R$2!m>YCBZN z{C)T*WV2WU-5#d z6Lj=B_6J`3wO>2V_NW=v%-gKIu+GB062GI&*TgQ9E7pwm=lXuM#Fk_#*%qFrUwg(s zW|5qm-8Jf~Nag_xWFIl$YfT^iHTY8ZfWEz`uk?HiQO_o1pdDAxlKE_40u8r&7WNZF zh`gjuAtF}or3mb4%vRP(b&fOfPWG&+7;E7qknHK%ezZNsx8vtIdC5y&A|(74=vRBS zS0l0cl@qHZb`AWH(#IyZpOpE@{_Oz!_@^%O6@t*#nUZb$(H((Gwu~fJO>J1ue8&Uh z95W>oEu8QufnRHSo4`{vbyGAed)H&H3H+G6uM&8b`lP5g30!ZsCh(+9Yto4h zL<=X`>Y2?{shzoWVveQmCOdQAv(7&}AQ_fAtX}ordN94{IC+1fFiDJrrjMH6O5@>P zi9^39etVg_)LdUXp=8@v@w|tvGm*&;qSW}CTGN^NHvNiPp7Bm56LKA~ka?_4_BNuP z1U|Z6S@TJt9XAR5q^RLuMGbVijx}|&?oRq%iw?!Q@jEshQ=52pG85l`rf#ncYpX3; zLb|}(!^z5`W?-Cr(+OnK`}|fKhkHYO<-UhLGCx_$>3uEP1f^uV{UM*U%0|C5KGQU# z&L`SO2;(TMGu|U}iyGcoStn}8L_N#r6z#ZSebtlgSl51UL@kG}qCTqm>VR?vG0+|p z?ZjgS#AwXvdRPzWCOb}WGTD1hV$B=WK_lgGPqnohxh{Fu^MSiL@t$zwyAnT%8~58J zb}=wt?IZ3ETNEhSng^N93bB<}5x!1#{BRR%pfh!l%w5ge=VS+dlC?!vqCPIO4tpjW zQO}yX8x0C~m0FFSt}IjS9XG7~=snp{-&Y5$vnl0wOzh-5N_WBeA~%oVcAL-kf(Ft;3?_p& z{WXb=s3(DY15r5g7{nbr!8+qln@FlT|BR@oSl?3A?UGIVJ)*8F8_;V4uLHl<^i{Ej zn1SwywU9QvD0iG--h;+;WsS1BA8T(mYgg0l=y|k2oT&@adykVjJaVBtAphGF|B6(v z?{VKz=A-eolt)~gGz=G4wmhz&WJ^BUNEuk^QGl>B3y6#D@xx7`#ywFx3Kgt*GIO=s zA$|UUo=QCld{e1M*PBW`tP}Ml@J*#g6Kl}H&3Z1hbH7F07!1{dqDeK!DcP&2Z(=O~ zxX9cUKC`nhksjUPaCbxZwX#l|BiMk>8|DNNzv|d~9OqM43P1j5WIlC#li1_##kn|j z*tJu#-PN^4Y=jc8}>S2B4d_U_{ zOu_@&i6$+*dz3WRJrFMZWI2`hJZpTh&W^Odg_q=q+A}+lme_6}%9i47{0tC@ogofH zaOWdI?>NMr+*0O~*nMQKX}3qow#Ih{-yH$F4XwQDQAN19XDAQoDb}m5H=yP4m9^lH zHQY@0P|YdbHv2SY0~+P2)HjKG5;$qEUD-y|h(jD%SpC-fy|`gL@nA+aJ;*$Dua!Dc zU!y*hY$o-2Gl5jHZC2Q_um|os<76B$!Wx1R<0i3t11=-#^|Kp|-=4StbJ@8Rh0b#e zZoo-I-QT2BWKr(e$*}e*Z&*Q_@5)-JV~uaPkD9(Z1R86mT$cT8N35cDKB6Y)Y@fi_ z4tyhOOw%=pNgHVAUc{QZoqJ_sU|4&D-&#RP?4ZZGlI=L4ohU|*-XQYjgi5xXTs@OO zMC0U6AcF~F2-wRd^NE2j;yP?J?qmwY#FCS~Wro2IbAQt~t(9zvh*GeUHonr-Rn}hq z6KKb>w_~g!&Q?+5yAk!UhMW0DouM5Gw^UGO)0MT_+JGKWpX|y8G;jkES(C-lXQgrH zUda&eZGm=lh0I*Uq1kOj9c#F~&PAfy?u6S4ZZ6nSvC7u*u9_N$cM_&s632IZy1(g`x@eTf%?=$>HOI6Zcc@Qh?*R?>HR=Z>@FeY;8Mul1$oT-8 zh#ZwmSw&*^N)-HmzA6XsR#KVU589Rf)kGcF~OQ@QU3Y`h04L zhkN~?_FFF@6a}Oew~a3ynyM`?(PnBzGa+Nm{Majc+*SX3}$yIt`N&tB4aLwT3ddN#1!U#lwL1W~@7273t%D5_Q>oqw5gUH3K>m zZ@eeBd$AlI=-EQqB=BJrGRFbEvKBlm>)zv7Y&dou@5$y{Ccxb2k$)&XUBgY5UmT~-go#Cy!yzwXU)xFer?gI_tO@gf9hT6Ubvj;LdOomvk6*PLpQ_D0O> z#!1^8(UgvOugBUw3c{tHX0#A<2bs*>;nJ(i44(fS1akse>K={D@Iha3Lpg}o&z>ai zgYzCIBG8|-8;Op>U%}WiRcmbU&a?MsMCRO1fY1=TY{uXoL)Lk?kDRxlx#A{KkFKvZ z{lp{WE6`XoU4$Kb!f_F9-z>GDNsl3Oj5WluR+^n}SbH(neG2q0GOU5_i$>J3F3&j1 z68cGLkc))9*fwbAx(?psLr;c#(92)1aIDsdpk#GL(^A*I^nLf;2W2dfaxzO}xW|V0 zNOdF}->%>|G2mo<&%A*HJviYx83QmFt%dy`t(xbiG?p5+WG-R{IsuC6QTiaBlUs@! z)ZX4w0|4cC2;<^Mt!K%nQzIs?x^g;|AQyo)Xgk*ylw+zsHN5s^|1E3iVt7!>}~U@ z4eJBuqit9R+7avaZ*2&K+dWw~bUagMFc9NwI-Fx_2K?wpKiV3c%stqkd9&-{iDDJp z`LLkJo-A64-%{pl(srHonsdH6@rasc!(AK1lerAG#7!)D)6-K5>E9Jt-zv9hLdJs2<9 zmNYQBFj~0fb0t#d)T((hb67(;Plv7=$NfxVm*j(vb+(uJ2K0R6oOpvkC1DLDnHw0H zTSq85wpA5zJtsextX9@Eev_yL1}!ra&u$X69DWk?o;3%?+EM;g%B4+eG6 zI8w()K@W$ZpO^XcZ&<758=3Ek&ljCJ5m)}wM>Hzs(vH8=w?X7bUAmEjg53yt6}7&! z9PT7Laz4TOOr;)CSE*y2oE>!z!y4$!s2Dd2E#ay?qjZ#qb;LoRN)7Jdc5+h!r|4`C zy1R9$yJQZxBm=jnHQ=^JQzHF+v7IX|kY31si{dz*CoW}_ohLpr$66|2C;PW+l^_0F zPwx6`zRt3HP$DWTBN;U zEt6yrGv|pK^lQ|IfB9-~>m>DWHZky}*(f`9GOUFG#E54b)@xTbtfyWlYOM8XrSYU) zG7qihpi^b`&ENzfX2dv0*gvlCV7J?lU_&Vx7MrfVx5wcFo6iaME4qwe1-(VavZs755N-c@sO(v0khB5bxxm^P|$|WJclyAkpYw$kCH)GYHd)vOD0guDVXtd)BUy z-2{3n^@jBxG+l2%-^7}_wZwR#Ov}R>-|4`wHGNg7A>I`0tMvWTKTXJc&~&|F4Rj`r zTaG>VxzF_{uKIJ+*Xj_9G%iVU<9HaCKlp<`=g{VrqDpcp zMuDE=fL;^0R4)T;K#P+#dk^c@*A?qEfs^(%>K_@__uhN2J0=pK;n}ayja%So(uTE@ z{*eTr2l{Pf-Wsh^UJ>tDDIbDPu4y0s8*xXkvl&L`UU$#V2zBFjeN{#sudYMfnki?R z2;$;4+$Hd7zlZfy>h(?sMJMWxE9)9FtgF$E?2e*dSsRikOmJL5?^$mu^>pAP>Pg^( z8|XUll{L`e2D*|>*A(IQqLOVoykzfGqiYXMo*6%rFx(M``>u(v%QRT$`kmmohkgWp zKXLCAkXB*xk2|()32Hg)QJWgpmLc4t1*Id?ff8I(^>k&* zbdA|w*A|bOG@&Sq0*Z20v6jG-_J;MoD>Ff6rdf)f1in`4bPY69vbATrasR-`lx#~^ zn;5n$y)rCl(?3P%Uz&~hK)+35ziEx8aL@JE6L44P&e{3~LUwD+)`}grN;bV{G6k@N zCfc#)jl3j=?Ifs`8`h)i&1!4km8Ix?0-vsI1wHLI*3L`dj$+a-mX8=ucOl)J;`u;N z0xx^tK7qp>>rJIj(X-~lTHe#1QG^`muD6({1!5r?dD4nzJglk$?T$0zS_b9@Nx$`#Ylx3RdyRv-(2YMQ_ zviEHgINT^_zFl|W-0fGRr6UhkIZ4=z#5&53h?_Wbu7{M{(JVL{ zKMG9f8n$0CCmG6Zl*M}bu@QA?oC;Vuy!K2o(aG?Dl5GKN87sr^Z9XSMth1BEiG9`h zZ4$d{#?Du`=EEQUaL+B+tyNq`$Q$DQC<`gs77I26D%qA2ijg^1vWIdfqiZLl9Vgt| zp9ZX~ZzF0d9#K1I8&OXJZ^5N8vkPQND_!U}%He}M)*ba8ZpZUH^)>iP65M;xYXT?a zEYOZeO<(C6YrPpcXcGM6GfK9olizGL`v;3`mKxg#O3C(*R@qN;T#4VE%qOv97d~HP z8^^!%fVh8=*tb*Ax)zv`IC1l+KO3=XPzTZBDD7FSQvpY{-L!(^Jx8`f|$k)XA3ABSd%x-y-p#WP*6puOiB z^^ekWxMO|P^p&n-UCC~hUCH){2x(gpkCS1=I^07X_meW;Bz7gBYVL$x@5KDE5Sr_g z0MM`g>aUKqe`(x5)8yZv<|5wkk$GFOp;%iR@}8oDHP6^6s689jtEeZ3uez=ynxk6- zDuQUoH+92(6KJ|V==o?ji8|I5Yw}@k#lly6X3T-6vJrKl9p$c$-mlO|T&u1F?O666 z)=@5XudF3-7HcKjv&U8h)Wmyy*ecum$H`#1`w;FSKF}jRGN1k}=sqi}Ph$7uk@?~O zCU~w-n1M!FGIt--&1)OBjEc3~a{H{xjZ+?Qzeaa019R6&)^`;3fOgUfh=_nj9L?LX zJ_%af0$l=EtnK2eIG(X_=Uwu|I?#?MMIB|hGf)0|1#zFnaYQ|=N7R$X1Fa=X*R8pv zajiHxvTX6a{5B<g4TTNWN33u;1M6tL0=VZ6JurFj#fu+wm>6N`UM^3 zO!BT?r|S*t5w(@I`|KW|QgjSegJBh>WFPAEu~HA~q3mP>I?9gy-G?LevYCO2`4M%X z9Vds!`k243ayZu7Gdn82MF(gwwwn8sUMsI^WkfKAdrutqRp!o5%6ya9lez72l)Jv< zNz@drTR@p-dVW~D=+EgF8|r#M!!x!tcu+UWFX%@O$h(7|10ex28E)v;S^&-G;?&zRYv_2e*( zL#%nw&q$<%EE%>$;!F;=LNr?Osj)O2lU2w{;QJ1IwjcMPr&15`m35%!=*@}<6;lM_ zcP!S%Y!kqau3cG8k%%=ZNmv>mMT2e@8&g42_Z~FFNF7lh{)OI7lm<#cGtiU3SI~aT zjKN3*VXJJpQ~`DFrqecNkH=>JL$@>lXHZqm4#o?xEvmCN1&|&!aWJxk3dhQo&-Lkjxr~V zxokzPuB?_U+<|tK!`o3Y0FJF1N;sOL^^qhcy9Z)V632Zl<(tHg`%Q^`x@*u?VI8162E0)UuC|we@d;t1+WCrbz45$MponG8H3b)DMJJTv4sXLM;T~Z zPR<+FwPz*pDcNUOuZq5-sAu|4Dry2lWa0=k-1hWjZ%sI%32BQ;fhY6p$^Eu&9BY)3 z-6Zf^vUcT3;6vGx3d%9BOYE3>g&T#X!dH9NXlG+w^>lA&SbN?;de!wR>J4ZRN7PPuUw0f1mEfS?B$;Z7O8%IJy8B(&To7k&ODLUd1dxIl8S*dxTGQBU>!`cay!`iv_ z)lqcmDm6UHU+tLzNJnaorHz#=&vX0A!c4Q3_{e$!2M zh!{h6`7I~4XI7Mm6HbU7^CxNEu4QP~COVPBWjr6^~UCGv4 zw#v4rp=68mmcXEcRTW!_o6ah8=RqGo1pTItUD!`JS%Xxv)oTlCnNY85bwDWwW^u|4 zPo6ZdSf}g#QfpX8e9hh)&;)LdBkd{EPE6BuOwdWhhjk}I*_6HF=xr(vnqrlLRBHXF zc(%awMXIC@&0xue zact7|{(5gGflk_^==e?oUqPp9WN*(JZb`rwNj^jkwC>2Ca4OlxHY^M{x11r)EkVyM zoRAIf4Rk4e@`f+cySAgEv?r(f5 z(BK|5egA>GM2?cJI8u{`0s3PQ3++Z5ag;{|EAcX3O6MFWD{-zE;v)ypOYCiyc71R? z2d-p$AW9n4DB7f|WCwRx1I>(#I$x!a3=$&H|acp*u zE)ElQh)*kp%G0n;+B|MmYfDXSszZx)9a@wfh000R>h-GYDDPR9t4rggd6| zHqb~L+?92pAs$oBtt(AuKs$keg?kmX7iS8coMAnPJDJpNMqWYOe2E%C`+gMa4aG1; zOI(QivBj5(_`h!u)mFjXFsQoYO|*oN%7F-Ick%^LEdyS(FkX=OzM~D9y-*`=IBe#o95} z-jj(9-KIAW=p*gJVFuqxi0=s66gI3AHPGqWZ(UGg)ORT>)`p(Sz*l1iG2ABTn6$at zeQjAwzOsil?b#hgeb-%Ch#fmg^+HI`pgvmL+O+H`Vkg7GX!Dz?<+|GwAL!$^e8pWQ zy1vD7PfyrQ5IZWCTBIsV1G=)_fVNr;w83XQN#^3#1RL{)b%>4sj;tpyHS&h-$h?xM zZSweDcaBJP6*bn(1ep`k)=?O(s%-(TL8?Pb)HiiyN&7YloSa9|dr`-lz~Po6Gz?ry z7s`sFxql>yXZGbU;^VhU`N;f^iGAHH1;{E}w;<68GfMG_+z92hpb!7uu)dP?6Hol> zRdB0HYExP^$WB5$#~H1pBrI2(;9Oacw7n>bxXy-vEaaYDq6XJJ9eYp^uhN#g;LxkP z^JQRFZIlDODb~||Cu+I3G=5X1#&>L!y$`BBTC814$<`uDn{GDQzp^{+4wNnEk+za8 zH^SX9$>cr9ppOIjZR5j}rF>m^S(tce!A_2c6Wnw&487vx9``t^!FQw`>#5XOC+!h6 zT{A(FN$mEHykd9VIA?@T))7{+SJ2KwJnD|JW3QVL|M(U~he*8+Zb{pT4lUdVVP8wz zdQiAp?5K}EqHZEy4oCcCS2hVe+Imgz@A?qUzg-|{&}FAmhZSW>8}7Zd-N&)=k_xokvbw&V%8Y95 zz&D~!(T)RpZOJ-^Sbi>zpJ(lzg38Egq|H)WSR}^h!$LYTJCVt*nIB}%BJP;X)A)Jf zM8RWRs*Rbi@O6@jlwzl`l^02(W>iUgh;O>G4eLNV20GSoyYa`g0WK(w4B}2E^F$oq zn1(x14|)OP3aX4{6vf#t*ofLH1MZEqZKL@hEo<6Eh`UidnY$n$bDOBu=)papSJr8H zi2Ll=fQG)*-O*_2nt6i{>I~bBq$%E3I_Ht3a2Qo9*@zGHh!6Ce61$warcJ(O>tiai zidD8&L7(Psmz9_P0Vya~)@uTXdDu`VjenD)tl#ZQA|Dk(Z=C>c$skt5j8Q zm3D8?j!F?eZvCZ5A!vtxWP-SJ!Q%~B$N+nCCK^S16mmP+Cg%<7viBWDz3N)xg4^*Z>#Ju( z+hBL}y7dT}K&Rz3djsv(21VGk_s+E?LsNAgQOj51KG~%CLr4jMu03>$riU?j5^JKa zKJsU-?l!K@&EipLC2Fj*nz6w>qIRhukRn?W9^4yI59{+?nR2iZwV9@C zC*js^G1<&_@rI6K&E6(O5g2J{c-TEGh*dYovNy8ijIv*a+w98ZBW))_LiVtyDz;@& zC!T*!HNJu~S*&Gv-u9e^Qm)2{LltL;M>*m$GYj`g(1`a)lHdA>_z`B7C+=_R759%M zSta>)!FCP&{=a%|gd3UPL>%QI?#9rtHo>{SX#hgbx&R;$_pC?Mep?RTuofg)l!x_3 z)NqfkW8G6^7Wm#t#bhp58?Y4<=V)elNiibiGP8{598+Y0Mwvju4gE&iJ|gX_<~&AO zo>}sxga)YTbD-B9d6=tN59DCYWD+I_Z8)grqi83qsO9RxJ)$1gek&@p1U5?*5y9q( zI6acv$`a|YunGp6H4Mj~7le)xZ?pznMmnF^ai8nch-c5*ELG0zG8qZcX{XaNxs9lu zgnLu0@%4UojrwY}wGnm1_n>(mYtm+LGf#{8B3yXbK97hZL$F#fZbS_<%0vP8NSogT z1MLHCvOWU0OirpIP$SCcvO34|=QuMb$J#f>S`lZ`zNaH-+zLgUte}Uo7hz?CJ6-$H zdn5-dFEcVbey(KOqaGH9YCOLE!24*8XCw3T#EJcw*Y8j4{4ifZ%T``id>+Ybvy|tl zi8sJqS&y#oC~E#>8`iaCd)A5CG0=`07y+-Q2!08ix?uv&m^s9W?rRk_);c=4dwO=7 zG}A=cN0<|t+@BUKJE1lN`fXjQ51y-a?x zN%L_*Vqvau%gM4R;xbIJT3`qjtEzsbmXyH-@0mjhD0& zxMR3airSl}QXe&a|G!kWvUa|y)K~+(irTm9#N3g=+Wje2n}m_#5ZWA3PfLa`(5=@t znHJROKURhhaW$u$?SZdm;dU(i()b;TpOm>uJzt?GluZ1KJ*GdKrNR&25CVPsX^|Lc0-x+Hu>*}S(A3Jx6@>Tt!P>SvHB1=Krw*6+8DB+M|@&3jgQQyV-2&rhi%@RI zi??HaQv&yfVZG{lQ>iC`Z$zybi*mZQ1h7xr7NS=;Q~h1b^geq7jW5cw69e65qX1xK za*eu~`k+wZNyMEf_p+tG#!^%CX=Z9=N8SCAOCBCkPqBvE0)YYTvxYaIp{y$dS}vjp z`t@Q~Fks!vtIblol!Y{vQS0bV9`n^K;*KlvyOTLL&h-Vh!XbyNkJ5{VSwV4c2uH&n z(4*@r^@!TrR?s7A#7p2;b^3uzt)U!f>C`=RRZMGYEugyL2sAnY!b^(7Zj-&+TWfm| zbhyjp)J^zF+Xr0=<*w#j0Eh~JvzyMgc+aPx}@}BAxcXo5g+IgcU)zDKC#a-jSA-a+~T&2v`JGO zj;T~5^B5`+*rjgVojBgUE1PvzxFt*`byIXl34{S{?m9#5ihx(w?5MyoN{kL9KKEmwoorYmNZKhEP*#T)YYT8H zM%>DgyR59S7Fr_8W+}(2R=%`HlI-vd3pq!O6=nvoA-<7$DSeaJH_aR3iujZXU!-=p z;pHzuvqDL1Rq8|?>j8~5tPE~OJ0(fQ!YaUarE=CIN!lb2jq4%?H}TE@()d6x;cPU% zN$i_a-ZG5`=K2t5#qE?@>|mkj7_FK5pk}^JR}W;8CzPwM1;##sBR-&=xVR5itRc=y z-9RfA*7f~if<=%uCjHir;eyDlrimJ8St!ubHL~~u-G(9PeuPhAhg(Q^vyb@T6mAz> zqsZ$n;?WTc5YC629^tl>hMNakQ*T7Q7VD#?uS8uA=Q=53Sc@fyEw~VuGfkWixk!L% z4%IA4)%Ax34-{iV+(?4Hk@*IC{o5w7*S{%PbA1C=I4arFiwz=UGi4ud)pkgcN9#c# z1FkU(w4=eZqo8jT^)=_ierKWQ)5LkQ6(!5kv-537{n&+MK#(7asvEGOpYi6TBL8#A~wxYLUm zs02Hp@5p*xYSoNM-4tz)+A7r-VLFPIy=%OUZBwSzSv2XfApzZ@1N27dSKd%2$C|Xm z?NTDAwtSBp3tLHI&%B(QKE5bJ9O#wxTCCN(74)99;EA;a&TpDAxsI-Ttdz>uN0LPN zJ`Y!gn`R3u$08h^)k<-Wo6XX-Wb1*IY~OCpg_;(E*aebr86Wa(pgVG@@RRotKdAaz z*ClXAuQT&n6S$mUd8G-o3#vwI$te1cpjB$r)-p|u$Qm0DaE{#Nq@fz#9=9uq88v#v zt#ES!b(hRRQBx?+fJM88YA6Fu>;fR0RWmOEy=PsersxuQtleU>Q7LWml}9fu0sOlV z7Q7zUH@1=9gL-1h`YvCpGqjx|$4<%SLk?ue6#js}%;L{6D@ut7S)y232YRwM&=hSQ z&7bygG-F)q;t-rvGz28MFVmj8SV7BL+-Rsmy`hF%CQscJZkKYw)J;CE!Z_B6Z}%(N zfGTwngyx6~lq8&8b3Xic(}CaAl^yfgmd`cAlc;E}OBIR}zR+NuHd) zf<}S#ytsnaT~wxhmyZ|>rpQvX5mFp9j-~96bLz4(Aq_`9JBSI zTSInmQ#95jFAUg8QP+VF=#{mEsmoO*bu6m3`qkrSzH7ztN<1gz&DG4*vuB%Cwn=H} z^Bx_Qx;u`d2lSEl)dNLlBvF*Q9kC8{`$d{h8H_8$$uwgMXe+Ee=xMxtg>T0?(8vO< zJC!Tc1xKUxqWV?g_U3Sl6D8m_xW$;*KvtUa0Er5&NKqxG_$KF$LIUe4)#jv>5VU5C9?;gsrEZK; zw2MpK6pf?F8Wqpz9<2dg-}1p~Q3XMN2JFp+V#$1PD~>0V`HaCPss>mSg@r<63YrQi z!ws>ML|yiF^jkJdEjbxzxiQe91#6~exs_PjkKnu%2izN-bjG>{jXyrNyM0#BNwDY((ty)o6 z5itM~vr6jU9&~YgAlSjmEv)QaS7t#CG-;Q;f!30(qE@UGEcMz2vHr^AKYS|YrE$H1 zdtPu;xAm6=krnsG&{5OfefC?Jywh=SUT5;NUwM4dNk=DR?zU*cC2%ZsO?oG~#@a+I z>uSaKtT~^JqG6@wesse8R)!$~0+B21O-Ww>*^RgGY1LEep5+y}Z9uz@Yr6ObH2u;D zMca1M9#AxMPTfL_3@}zZHrc;!C}P_)rGgD{Ld`SW`3u zI@Ug}kJb9R_brX9Wtw4|Dm-t0L%)i`qpnSw9TN;0d|)LUpBnR=|7u?EN4KmR)C90}+lu`w?YHfW8QU;w-H6d!|g|_Aa>bBxt{yt{ag_-L5vE z1s;w-^CVq>>-vf{!Z_5A8h;$ zQlgkv&7#|v(y!W~RT$ibqSZn9+<06{`gLWl)?uo)c>VwF-94Hk#}R~K-jS!#8D!F@ z96B;}02=f}lgE*#7yV(A#p;>aAMP$!da8_81JkI^ipYq}YG5f4(K5RxYDX+L5N%vd z*<-gw(SkuV507i9s2eA39iYrqAb6>1u@EW4loJfbrahX$2Mk?=;mMDV!q+G=5EKmv ztb-P2JRX8vgKsN#4A3gX22UF?YorcXjjkbPRIG7rc-e_J=}2R2fnXPjT#_~#Jifga z=u|UALwkr`n=vyF(O8RUk2TP$+0!yP!7?ad;>40uH&UDv-HUYJ)hz(!<4*VL=YmnD zIUe_eF#B~*q!x?fxQ^wO=(t8Vt_@rpY@85OZ4Eggh}l{MY*-Oro$ zVbz8t(bby-cM@raLOjD)T83LYia{`9lcn4n(Q2!zhiDcW*TXVe@jFM1xPWbfSNvko z)mwt8d=`>uU45HgBDw;-5nYYG6D=Ng8XA-f88^Z*M<2-Uicl8=LBB2h~TNi@3Q)Vt&lS?ObdvfBYdIMee&^^t0<-5qI;%F*- z5JXH^?eKN5he8CUh%rL{E9bNfHyeMC z*Q`i3LSF5V=XO=(0~X?iQhS+!3(>Q;O3_kcBihVvZLCCF0`9b7QWvL~#jiF-Q)=Al zmJ%8UM@hb_JGxhO3qVnh@lm(nSGq^w;&-Jy)Qw}oH#m9{E-ETa(JW5!Ys58h=sKe1 z1EMohbf<2Nt8_GO_<4hYcY24UQ2V2l-@UP!KI(FmQ< zvl_=J#&Rc_GjN<3xW=-V279MvOK>Bt1vyibvgL!IP@VNQiNdiy$F~eC(Jq7Vi$ss2 zMJV@t--KlYcNC3i*a8{9SoXx#7`pw*1)>~rSWj1B}P>F=6c2uLTa~3M$@n_-% z6pCjEV@6FBU2D}`OxIaDt{nCT+*OJ-SnOjOXnFcnJINkN>WPA=Ql-SLktM zm;_A_FrpX~PLLe(&J9`NGPPd(W`L(;mNpVbAwbrc_Q-iu@FLL^9mvpzIilUy5C+qb zQHbV~tQ&OI=#6L(9}rDY^392t8{MhfN;NIciN&-gCvZ2iIyas2Ef|THpWBXkPHRQ) zwRDWT4C7{IYrxko$~~Q%jsm=>!5~_r7i05pw_g36z^7pouz~J=)-ryM(~5W+fAIZB#&vF1Z7NA+7hpN= z2t)aaboTDi2dGhiDfHnKzb@-|k^Cfj<2rt2%PME;GjNSBTmwyxS+C<&rJw(2c4B~o z{?>z8PUtC|D(pdlpS^ho4_i1(D(bc`)3{prbYE%NGCB6D<&m@21Cf@`u znbEy69vTBh^-HSztbDfBRgw_r)=2k28_1xJcMXXQBtT>#QHhrT3PDFNk&9(VrhPBX zSjI2hTHq>V%d~KQf?tne^^I**1>kE<4Xx+!pfO?|=^B%%ouU+tsox>ur^%tKVypeE`j85q`?`??U_UdmzbV;K%+b_)x1 z1S9E1H+xCoItQsZjBgcO_SU7(QRF-F~V{L9*AXEnkLfPSEWZdH^VKHj913&sCfk1s>yE4wc3* zK3Wjdp!A>Xw^fjYr#3*&Ye7Bb;PBdVYPEK~5EdwosY(E=#*rN01NhRJcvNNWlHc-~ zup>4>(Y+MvFTeak7tG3M zaqX*NCqAo9f{&aBY<4H3D8kFt&n4k&72Hi_uceKp-x-&0K#Os~6cr4OaB~6N*g_7k z{|AKa~AB6YMt?-K%+F%BYG%^@jQ4`6GLT#qSO z%J3^}St>sTQ(zOS6QfWqB)gUju9p=)Xlz=J=(}mJa#o;!{`u#88$0j^J1($^7wklq z)j5&j7S4(h4W$=}?oDZlZo?!VZb)o^z)H?bfVwq~H-4VL`ME9RDsYV3BN$ow2z+Ba zSH~SRj5@bX=Fpo|^jOAtsOTDCG^_}QRAzFwW2)F^IKHIN56c1Hrb$STTlv3@TTMHW zvIUPg?3eXazHIVkoR5&LkE@S@w_REz6xbHq1Qx|u7M>h%nVf7@dnZJCtSN&k~2d@lK@?;lff>NIS3fp10JVvRHo1Z2U)fKQHh;re{8zA617o=ZM}O++PtRPkBto2LZm z*LTt&tCVuAKt34aslND=3&h}Jqeuz^T!yrAmqxc9qb>}8a!mmjypLb2dH(a*jb$k` zEDJ+0FS4v1;#cY>cxg)S0d2_BEajq=7jdLvM=?^E2p@e6XV`r2iH#My&8ffqw-6xD62gCA zkN1w3`X7hVpks76dTGSwTEmL-fKbF9mdP7>RCjaYuow5Q+p zpw-rqoa-3j4DEay{%R90Fv4}Qqp6^AMHb7fsZ<<%KIDXZpqp=3^(uB|<{M^~LOMWI zTe6A7QAX+33{N$cn9b62^#rwkbz=E&fQA7U5-`FlnctNjFEL_W!}YqTd9#zDuan5? ze7ka;WSzW=yS4OKDXs>+C}fMWx)K}9Js#P#yqdPn5jm?Vd=k+k=lX4!=iBPCP6H!# zV)IxGUu*myb*_={ap}}|6P!H9sFTqF+IWfwzvyP^xs9VZeZPOVboFS8xFuJ|fe_=7 zeo0{`J>L0qstjt!z;|5P-01W2ja6?K*KW;hGymMN0A!#cDnyr=Wof}jv139`%hqd* zW8X_NfoL-z2|zxnK!Y^K;SBA3d#b7etrN2c;p%*ti@veU5BU=)*aF6tZ(fm~*YfEA zr5WKT@OEUvlZ2edOZyak&c?Vjj&ZJT;WQrOj*u}h{$A39dfa%3SlN%Jjk_VSllkj# z+Q~ZM+(o8!U(EoPqnI49JQU-%uOKZ1#ly0d8dH~7EyKsq+}g8~vq3&!w3|rI5Qa0f z^X+!fxUi%21k5$8TaX{Z=7(I9pYsrj#6YSP5^Mxs1s7*6I!hO@oFsXDuj*qto2!q; zfgs_PFyn&fA#=VL*H{J!SjgEP0dz^2MqoJAdF1SQj_R!6hCkkIl+Zzg#)mNYQPyv1GgY#7&R(72qjz`i$EJft=G_f*{VO3{M&CN;5ist@e4Pm4L6|aby?+Fokv{j zZs@c4_G>x7&)bekwgfKCSjq^zWE)Etc@3ntO#)byo%pZ6{wkBLcVj%6Lnff^N)OV9 zzrX9{K)p#GBk>+bD_#y5i67+pjTBn=(p2kie&c*Zk`r+LYPv3rYM|fpm+iQJ1$K zY??u0=jyXNtCSDvc{}uMidV4@&KK=}pnhflo(4nWc9Ip(^-hLaCv%s%Z-u6i9503+ z6dNnW!}9E;B)L7Qq87^l>G4P`L(IM@)2=mQn^ouJtPOJk=)Qz+zecyxmcTtLmVO$- zT69*Uny_^HdNJ!BSH^49EwI{TGp<+9)ra)HMuC#AQC8By7^EBTU>^#c3@>pMW!_x5 zd+}VIozHf%P8+#Xh41{X6wepUQCv~Blk!B)w{O-yX-@?j8+5mEh8WzSR}a>fXR34G zL1S5XukrHb-q%RGHSVQ<+7vuXva-B}s#9i(I2`-;17E12F&x~?YGIAVOIepNjpR(7^D zSV>&Z?;jajH)dD;ie#f$z{2*Ol<(S5Y&lx%5pp}JdTco0(FU0ohGnH0ZVDm{^+LAQ zQi5~J%&$P=N8Q5OvvjMl1ThcetE=nWn3C3xeJND{L3aZ_HKiUSAe{<4ZZ#(ijZ_o7 zjzj&%dzp{}tdwa0)|Z`+6%VIdH+f9xG-{@n*iSLds4lglPvo|f@_R=-;C+G9o<{4(4bUVl4 z7ZLxue%y{z8EXi;TotWhMKabZ#;&Q=J_Q2$nd&mLRUOw`>ffAu;O2elP39I@|2Cv2^AzDt0D=+k2K2}W@2s*1u)rVHuL&?^6jRQ7 z*|B$q%6YSQhSr!hf46WuzgzH&2o_yqDIP8@Ew!4&E8vY{>#{m)%&yx>*{#4q{=P;HVB_7N zoF^sJ$G%Ogf9&aY9xS7N2+9Y%Tp47%y`0PJeAiDYyFA1<@}5!qjfz`nsJf|R7L8wT zicOG)c)Tw{D$c8|$hw$VLe8#rt?f*qA=@e4s(mDuJ#zo6`1R0Bf*O+WOgN70k+J}*^XZyl--)6bJG6!iKQZ<6#xGHS z{P9OWP4Qb4+T;v=n&Q{y{)A0)y4VLBC6XgHD=2Q{c2uk!mwWN+Mp?ILQ}IyDmL)Us zS|f_B*Q%>xGJj=RXX~5vKacjeFoQZyDHxaec;spIpJc9Vsaa*am$H3GcNs$%vB#+y z;E!wUG(z4H%U~xrycnH0BFOM5qm)3alirCeJeuF9Iy&)=KQ*}hB0CCy}@D@VfO z6s?k!imO>sY;{grnpMko2w0R`0K|^<8`(^K-aN4xR~g%nt8rw`;>f(@@6kHaolv^& zMNKCS641!4ymLq(*SsMy31cDQ#|vs==a~@K|MVtdy14W8ubt2PW{X+#XU>tEevuWw zViO?}MJr~JM{x_OB3q+twBL$ytrwORI6s;Aya<1Tv-#qwQf|q7kLmfL@{msHs(Iau zb8rpsR6{%5Z>ZPF=k~FW4tgXy>=>m%`W;(#Lf4K-yJLje^O#LWnc4jA;$H5kzPP&> z@at#fwH!&<%Zxe|`&3>nc`OjczQ0q;zBHuY`1}y?paU8(QE*8B)IcT**b)c~c_ZG_ zJ8Ydqz4swcUxtg(!A{Eo>NCj7Fx!iRulg%qx;ReF5Uu9KELU+0H%h$jPQL;Wk8I4P z-MU&V~L)`K}6}=sw9Rcywl5QD#<4+$iv^cLWvGX zyhslNN0>5vP|i5sM;Ex#K%CDS&9luvAEW-{eAB)Ak%=u^CU3t3TL`myojkW^o5V%kN;~G3!t7aE$a>I=%*G(OLKjN259uvJ5=Xw82 zAVBr1ydM!M^wHsHB>!mYm>9k9r1SN!>v=OcV%CFGKV$GU#8K{-pzpKHDF^7z!wNqY zww)(KPU|P=8h+oA=>%xguNu7Rw`aV}i zI0zgB4gv>(gTO)HAaD>k2pj|s0tbPEz(L?3a1b~M90U#m2Z4jYLEs>85I6`N1P%fR zfrG$7;2>}iI0zgB4gv>(gTO)HAaD>k2pj|s0tbPEz(L?3a1b~M90U#m2Z4jYLEs>8 i5I6`N1P%fRfrG$7;2>}iI0zgB4gv>({{sZR`|iIf-+*ZV literal 154542 zcmeI**}i2*b?in-RxosDelv*H7xF=NJz7~}to5i{1>J2U^!|LYz9 z_y6>UUHRYr|9|uUH~Ihn@$cU7hJW{l|CRNIH~c^D|1baZ8}|R-H>m#UT+Rxd6*wz! zR^Y6_S%I?xX9dm*oE11La8}@~z*&K_0%rxz3Y--)VpT7Iu?|J7t-}&~pzvJz1fBW0scJqHO-|>!j{K=pE$zS}%2mkUf|5ASs zKKtym&p-eCcfRwTa5wnho8x!CGuL?m+&Qq@d6LdFr~EH}`AZbO@r`d_`mv9F>;oV8 zz@PldGmyRc&2N6oV|M!UU@WZ=$DHZzyR_O`dZ=RN=B{qKLjmGh-9ed+68|AyUy1Hby!uQ-GL?L=_y zdsKmBE>&&F685WK{p!a*{&8ewC<<@@^w2{OJ-9E7haLj$;VV~m*a9x>^nC2G$B+H* z@yB;-W4|u0s`H?c4Q0RwAKZ<<#aG-;VxQzVa3Ch#&v>$FIEd zio`!>{ZW>OZjg&;UYGd3_~J`n{Nfis_`wgp;~npO;)xsdzyJOR{4Z?x>G|l@tJi>h z;)y4oyeMyd>s#&8(%k+GivPdoJ@0wu8T<6n^6q!PTmI_lDTVo#x4iXYyeBONQ(V1z zeZLH@AkT+4zVUvwHE{j<^|!wDkN^D7|NL{G`<(Yaw>d9_L&2Tfb_ziJ+u#277r*%B zx4-@E&wcLmfAv>?MSmhc@W6xj-FM#`-}pub)^=uCW!95VKJ~|cjL+NN^{#jQmwkEW znP>j=qS$i(Y+oSwumAPG{`sGOKyA(Zw|((mR$^;(D@Er#KY#{A4@KJ%?_ee35x|G78Ld7sY`r-Ll` z=}&+9^{;>ZV;}pt#Cy}5-emuU*Z=S(CgNViPe1*%OnuLL-mMQ1?|ttx?|a{$zRynj z{`Utcb|3oChwQ7L_{1kj?SSpzZCkL-e(h^tb=ES)H@@-BeeG5M4MvJn`q#epHQl_9 z_4kwvbwcyL`0Ky^>#Pck!7?zH87(RcU{C+u*4ta&@)j=?PI}SX^ONrnKm5q!k3Vi5 zTC`q0lHHr=e^}^tISTyk-~O$muWeI~*qLRAnrJx}Nh8@ExI~7S*pg3Gh?TzD>7xz3bg{ zAc+6T2)J#|WRVWk`_o<4?*6aHT=L3U35yOcQW6v_AjSwU&_DUfPwFF;vNL;1GI~5X zwr}fa_HXh1T)T;~frH|4(@AQnZAOeN7>g&%Ky7yPEfq8B_7{Kg7s>i;IMyfb^8JY? z-h{hz#e=(7{QV3k0UjF4_Wo};&42Z)UpunWhb$DxE^YDeQ~1q9@Kz*y&=5^G8vf1S z{EaLmEPaw?$ii)lcFU&iSgtdU|K*}grf4dmsoTNguA(Dwbhq? z&~wSQ@9ssuzuzMswQijipL%NdVbFf%tz?sz_58Kk9Zu}+|7OzMq3dTq`x!ve&1?68 z2k!raKllS7JK4H)lA*u1?nI0r-Mm1PyeQj*!Icp*PJiOd9R-Vk(D?rSc}y--ThUXo zT2gWnORXh$57v3y5=yEX*5Lak^9=5tSBnnP-+M&j3lMahj6KJCwjsF18F7KmNuGMS z3;FTKpOE1D1LytDnfiSB%U`j#6Y5_tbbHi~e)MC3h!@#E+?D%$fPK@Op7iM^neu0U zwo_6E+S&~5!?c>BedHq_AwFRvGPT(rp>wbTM^y{S3XxWdaavDfckja=)=lSG($dG% zCv|Qa-y*Rvc#<^``dxCo5`u1)s08m4wH--bLwQgKA#>jP1U=smJn(?eZf~TC^tXNe z=tn>LSGTcq_y<4ufz@skyK?1Gj0I)i7Nak?_WAefYZNbNgqggM!rr_xg>J+l3&fNR zTsns=^%M_U36gzVv@1F&>8S>;1#43%42`K7yK(m;=h+OhAM7J-XXxqK(6{QiTJC6O z-P(w3M>1Wp;d}3UO1zE_4kL8%ejvz=8&B*{ao*-v9PK{!sZV>;`9|*dKgVrED0BGj zZ-1u{B(g)7PowXA=ex4UQYMK^E8!=LC4zA?F#^Y+D+wa)Bmy1X_Z|Qm;A#Nqh zbh)q5@^Dv-x_Ob=>twfAn=k9^^9Drx_jXt3n3s-2%e&t7ZXYz9KrB=tc&TQ;O=uQ2 zMv_eY?z_P!pM1)fMGrps5a@4t%hUS*zP-m$_GQSk&wk0i znLTy9VyA<(;c<)h;CkaKBis0dhP!EAJ~5?f15L&?uK=WbQw&Uwfl;twF`7ACm`koSE;W%TH6nco&BJwOfi#TX~dcDbbZg_?*X+Lp4>l7x=sX689`Q7h+@1G~ZeH`$X*?*YY{e6ReBi(h>9x3BZ}>V6wUSoZ4s@8A7|(GJ6ty~FS4mEFlk%})mpM=z32 z$`+&;Z;SE-z1Q;9&p1twgLn_4W6HtWXxiqvrjZ{e)C(d?|wt$k!#nkJIlTN^2@JBg8MnFgM|IW=_}uG z+I&zZlm*EXi`Gk7>4MCTtpn!;l`xkS&SiCoEPI7+evB$*dQN#GxZ3zlz?sY3JDAI* zTw~&9=P8e;7_;NY$kK`f)1_m?C+=i-YJs~Y1q@;ulT9FVy}whVa1H?ky`eTE{M zTgl~vh#PN07WG2evsw8IR9n?ym?ND3X=ACXV#9i{7 z|0#)U5}zx75;u`VPL6|X9ACdU1N$OEP+pxhfA4#r@wx2!_3IBm{D?E#KEc0x_qcuA zX(w^I_HoZorJ~2)`H5KRJ%(D!On;l+-{|85qnTcj!X@c!p9I( zNtt|i%wEekh`GI#E%ZE_I%67K;QL7qr#Z)XI2~@9Uoe05Be{?-qTl^D$}qI+X#}(I zkkoSA2NoS{n6k;1E{UuJwSCo54eN&=zT)Snmc-rQ_JPjf>d7acvT6I0#9ERZ;!Qg9 zYQJZHoddLjo)5&d;F03?0(V{}t`n4}Vgyv0L`xzE0k0HLCZn0N$0$$e3vrKhwBXJx zsm(h*se2*L;Tghi?Ora;CvlSkjW})DUg9sk^pbK1ZcnNTAh4jmvTUN!80PrlxW9zP$uJ) zmwgO04`%^!GCge{BTkK!5?^rhXCXdgNpv$_3Z&2^r4qT+)3#tt>n+Kp*5bz~h&vRC zLUO77=>Lf)o{-?);J$?M^N7pi_Gx{;Z@=fk{jbVC`Q%duG-+n!bJ7{p`oJGya*vZ+ zz763bxb?kk%!502L7RORA}iHA2>75(#O&LmJlDW!;+>iiXQq4Xc)nYyBf*y~Juh+f zmUz%>C#eNv3jQFQ_onk$&TKT-vZwIOQ%}8mMEBEDKS#a{Zil*OpZ(JQQ`PR+AxQWSa-S1|_SIvYW}d?vf%(q`_=<^}4g z1~;GmdY;c>_H(t7UwP$~)5N`1u3hsr?ETlTKjz~e|E(y77!B?iCP|adHf>>=lqXy| zn9lLJu_UyEh=cp`luaGkTTd>9HI2fJ!GC3Goc(Lhk&CZv0;;FS#s=NqI>SDWh1`3SpJ%9AmO5plOI=mObRxRP!!- zK3jXva*#O3;$$42QOq1)h&RV^k4guLM@fCG8By~d1$;f?hf0cJUGi3Yes1DB)px%0 z9Tvke+&){``Mrg>YKu0eV}QNFm)jEDI2M&iId7KJl;d9fPc1HG2FvqFnLQ;c;!<8f zPyGvJF&2)mVZ1-ere*2243bLUOJeUrrEjurtjgi+XB>I00v&wo82oNF^@i zRBXC@2KQs5eRl5x+JD35*RUVL-AXu!+i%72R|v4G?GM|1+gxVcf^IIy!|XiqKbzI0 z%w9k*lneS*1z(%aQ}7_z(pm6L%2wJIb8c(kFD1S{URq zuPBh>l`lG8e)(lTG82MtSNzXs#*8yj8-sXnUGNAEYg1CU* zQZDHDpQW3KOrbRDiI|-YFsadWo?=eQ?1MNKWJMWcQjWcJSRUU_k<~RlnI5udf{Q{> zOPCEmYDAf+bQ$90)y=ae;ygMwVe7%ivFD$EUSsxiU#Q;L|HQ=4oqarCevM6-PGVM$ zr+k#-c23~p;+}Q`PS7VP>&zcf2qCek8zW;0erp@r94|^ z&t;s0bER={%w-%Vc>M3WU5HO9*p(=9sR`Hut}?URrMsRoEKlH0hWfm0D>k6_xueG( z_wLsh9oRhLPgFI*J>nP-wC_p8i#s*=Y)m7EY(Fo%%H!^rw7jdRLNI8o$J|~vcGsb<; zhrbf3P*Xs9DhJgrj>(99dAQr2bEu9VXbh)HM5Znjv-Ewg=Vcg)Um0yk$)5O0_bdvUAeOR!=wg;8$^u?pC{-dj?pPH?{?Fk zlo!x5og4mLQl@{QYWr=-cS}D(eBuuANPP@9sSV3Xd$Qx1 zZ&Ts+I+hSNIgP$S^;@8_+gCg3GeN^TLAz8sm-S}$na-wDxix}+J2dg?IsVRPe_ zxg7D!VvA|E6z)M|_FU|aALBB_Pb9dI6Z=$S5vl@4Pj$FA!5O7c0}DM3OE)MLhbx=8 z&(2x|c*~~#oc62qG3_i42=`FA5ek__jAuZ z#}g4*0J7V$oJ+>fn!#7MT^f%>HnO5aXJkyui>sxaHJktwta>WIrpYnU7Hy~O3z2zw zkf!y#l!M*oIEy`JXD_}T3}L}7*ov^^_(9@<9-Sw2Ae2B+Hx2bM4o{Hv`qp0D9M<^c zlTR5FJGU0Z86=bqUeH#ZVYBuY$}UaUZ7LBpzy%PCu_Dc5oaxRI>zG3HkV7e(Zx7{m`aOo zmGp${ZXJYm5bKG??I5Qoy#wL`T-0zG=q1kRu6T@i5`01r@zh|UV;s}T?i|(N_Hm5Q z$>oW-pbe;GIUPj2Q08YSZ-X-R7Bslp6-E|ba7X9Mu--D#a)RlJTL*_aO?>gNYgK#W ziqSeEEczTvb9$a8o-|Y!cUs^!rb&a_7iB((`Axz}xz93YA|C{u71%XtaP|^~%Z53P z%2LXUZl^_FxSSw($G4U#T%LAmS)an0G0xa)Z?)P&Cn?+qi6;})lUnWI=7ZEGf}c>! zZmipZkr4`dyIp5$K42Zb^^h_BZ%~UdMF{JHW}KFEi{OrFo_=sUQCd#BHv?J1Ttw*Q zRE#~vOde&ojO@pt2i(FjxH+6})g02=A=~vq%9&!D$aQQwyxpr4*An}b<+OmuWIqk- z9^O6ZzzLrdnhsgXOW>tE4WdmA3mtAE2YT`g1rR6nB4dPRl3iWgvfFgMJ0Drnxs(wdani*H-jGr%nJ#y$l}jzqm_AJh|+wx0%c&+m5L#fZ-b>&ClC;c`;0 zy-4aZxT}29EnH@H16PP;9m6f-@Y!W{?@8Gp3*{`W&O2R#_%!9l8zY)bd#lnS=A@Qe zS{yQ8?=t7Dz4&(Ua*0T=TGR{iB3_J0Iz_JXfu7VmMm&4?Bp%#avL3=3<$%s;6LHp9 z9f&`tDQ|N*h!guF$U)IGR^;$a{d!a0j=#)1y^8IT+1Se&S3-^mx8z=htNA2e=!l1! z8bmZF>wfNbH%YC7ZlUbii8$kTI!1h0mSQd!|4Vin3u2d3jcHf9D({T(`%s*0Z>z-T zM3JBp=0wk?5&^fuM(~MXLT`>ITZ0?W$^@DEu&di`8Lty-OivWQ=9iK_?9#740&Muz>R@(9 zYQ!g(?&QJUZ9G_;+WE$8VVw=Z2y?&_={za3o6d}SUbr@lTZ3%uuIVhcT+pKo7$0Xiahn7Tqf>hE0kdx*0Q^)Jz49V-FpFT z@Xj?ISSU}p?8!8C*KKbdWIdDm;2wSq#L~XNJ-CN2kDR_NXvV>Pd&%g@_lb+*57sGe z$$I^5_=Yks_XOLw_7*qgOJR$g|LEmKU&?1P{WB0dIM`z=|| zy*Ku09Jzat@*HaEaG5c03A*p-WOULQ)*?6)@;3uv89}r1l!bhXqk-I$G9x`mZwf!E)O0Yzo1_| zhrRvnIc(<`hL;S@>1zwRe6PQ@1o!gd-X7An&`Tu5%NjeZ z%G+VHwC23iz6{*-nTWSfxr?>Bthamkf@XUetlLGh;MO4}?Z&CG9aBqiW1S6r9>$W< zJ&84=lgp1i_Sl4c?b@}g`=U_?YXk0OC#OKfnIgvqqEMRMTil2**$uZwC0q9$B=wfp zv6e}BN#048{w^nlg%R18)LYQBf7|t+_VW0#%bClQZ*o~8D=$uIAI=-g3DmqJu{IUy}G7aN66E7sR>D zM8O@(>gIlo;BJB+q>M$19Xn-$-m(T7bU6-aKtHl6$V+YOL1&{`NWneDImo)HUDk{c zZ02rLySMZ_b|kwD>nI-|(w3x}u9u@i;lnmucGp{caPiwt-i?Y-B+Nc z9Agi8_wH6uZt(_}*VyhM->e?IC>B6d+ps3(4?lUH0B?!AtQlL}vb(2otlMEeHCZ16 z&5a7aHORh5Juii$!}8QIzHM*#%Y!Z#$_Hl;>$!m!_k2ggUC=QW&8&7J}D*BvYot=DATMlVn&{+4aUDk60_c+#flhl=Z3R^pxHyor&^MrAi zptI5z+>`Y-qmO}}tOHt|q;6hgmv2jO1awO|z_r`qyN%mAxIw6jQ$d!D3!S9o#NEv8 zPTth+t=a!BlRBWOTDV)oUEws4+cK7w^IVcWB8PAEWLMbOxqDlP(|MV6q1@SPl=uR= zE@k&Vwuk3sJ>S%2UC>SHyr%I@k=G2Lpk?lB0KfJkuWX&|2?kGIbC2hfweSz(UQ)Z; zII>CYZsS|lmrUwotfOsnXDT`Epub(#2SIm@P3}cpf6BVPP2AnU8BOYdZeE9SliKUG zxaZbg(C`7RIG)Mh*Al*YCF^y_cW4GTJ8{BVL=*RASlgewS7SYKYoAFS&}y5*GV;P@ zk-dV`wqh1;l$@7r5s76P_Sofix{%dA5wjP{^D?-}sC1v1UQN(6pGkcTbY9c*;2qYX ztVZ1H*em-c-Pc-{!91RsmrFe4xo`wHHCdo!4_{Jy!JQMD?8bWgroJWXt@3G!)L~7` znJfowJ!c@t>`s>sy<|iUbxS02IVrOP`ULKHn51q-A4}?FbU+t(D68>Rg4_FA&fb!> zJ|5g2#RW2DSy;Q=;@)oK!97`@NNQuw8K>IQj>7xA*?r}>@QsYAb4$-<U zE$c1iLcb(v9v)eo6xUbSq2BcQOTlBn3d%+tdqRi$>%nH z$)uh{rpQ~HhYRZ>o&vJrwjSbqV>xYXr_(Yi2lN*AOlo#K%r>4qyvuU&Hm9=7Y~Tl3 zqa4 zg>(XX$6t(vaxaq+OF9=f&^$~XKh?)rbGVNL)y zxaq>0!-+XOQy8lBgXHHovX%n zmbQ?BUBod0nmt*^F79OXHm|oyJy~ye?^5nNI=JVX+KU)#-=5j49m7%$6vInErvA|EsOmhCb5QlOJ^cf}a`XT~{EZ4<>lHsb=i zxC^>QLC3=rphJB6oIQMD-LrRJ)(1gjt@!rLXR8a;>*ufT;f{ID>$0A)SDDGExTW@F zUEIf5FN1XOIpZ<=80%;yioW=25Y~*H<)CqFI%M5ia2M`03OWWEo7!2H*~6RHjI!ox zPi6B1H7>>7yiP{v9UaQ89l(lv=5@|y7K5d7dDeuQq?)G-?wQ)qXP2g90Zr&)`4%2MfKY+3h&)?3RXbF_mZA8ZWkW=&XIsAatvlyp}&)5U=~ z@3fCir+s1CjP9nr7|CmTrfg4T{82)g!`q~ud-%bm&W_!rme)ybSa+EBCE4xMRyT0N zn$FZ5R`ZS(yaqpw(~Ba z)4>$ZIViMr%WWF!kR0rO+tbuE%F7PiV#`%9+7>iZq%e*tayjLK^X|V`t97;vlGHhv zS$nr+EzIh(uy)z}mC-GB^0aUJcc`trCt5s3e5@4?hjkMq#9M1m(IWNu&`A#(2j^W_ zyEG2gA=n+20dD!WeS!|wykz%@xO>UQPzQ7m>n{kp%99=#;c_F|IwKnLA-@t$~x4pF>#w+A997} z9`CMdf-~9}Lr=t$%fWrD4)NlSu}$r82Rf`Ta{A_f!y0HKn3n^*$_cz1INYaMAH#i& zwFJ+t1$Wb`dS1rJQ+jeTdEL~uO9yxO!X0C`zwd9MlgG2_>OjY=v3LTsmWkV?#b&P# z%1}PIhfnAs4thW*yAMLYB=N95h#PC*EeYcXbl=o;aM}szTe22ug__wqad!_7>)CDQ z)S~JwFN=fnNo{U(zCgowp`5$cv+?KbjiN?E+q$vfPB;5ua~Wu2N}LpSZ!sqEZ0Sk! zgP_}ZVpngb2eXCO^#u$ zp157kK7DYCc}u%bF^r~vT;(?ZE!W9<@@2b~yLy&2V~)v=4{1E;PbjzMfP4vA#w^9n zKs?Z!<0US;Q!crsgTCM{>kzlMC!Gzr1x=-}w!cNaus#^xhViZB(1J{~cG0W;1Vd9fECdPyI4YGcyVQ81L}$*{zAn9u_v(3{}J-CeyW zw8bdyz{NK!#8NRx&JU%`pF~X}C0lnuhw>#^i+74s1dIiDZ_WOd?v}=Uiakf;>ckzO zqHAii_ndcom%+~)HR@P2m^RE;IT?PXOef*3Qk7i|wpw;eex9Y4l0 zi#|LTg@`8WDz<=5H&4xBjX5u4&)H+oy819eHVT_AC5_R)yj;4=2R=_9GP0pk+*N`m zqylbP8<}V}#?B+JqTQdt3~RuP;dd{fS+vi~)Am6MVV&$=Sf3tkxjQK=pu;GEh^4HF zFqN+wQH&HGnZus87k{>wbKdBmnhz~WWK(;b+x9wN9jEve>loXwBd8bOf+@VzEr8ap zF+0ajUC)hK`*w|LwXkSv2THr$*7$vjF~>J}hBcZnyZ(`#f=|%tqbAWDHumD=>~Pv) zqh(Tc6L9(v;_ey;WpMLHB>HET8Hzt3qqvpgSM`=<;MqtT9U{o|bK2%|nL6!>qJ47N zZoRyvkr5^fb{s2|IpZw{OouwgI5@aQx2#)&PuxXZBX`s7AnQ5TwCl++pRKeYR@a9l zyV(Ps!AVje=&vBiUj^pxVb0&V%~0|eal4h`uNBG~$TF}1pbveuO~7t|KBH?OQb(xD z9*G*!a@qD{(H(5hQ<89S*C2Om7vST`6QFh+(=?JgO!gOR!-mog(1AXfBIo77Nq zirNR;fX{rGaXqcOGv8dE829dt`}Q}tES<39x*5ZMIG zIA^Jy={j%Qr?GgO0aMRSCdAcl@fIDa3L>T;f9g}8`pj#K7VXwRpeNI}!hr$2p=xD^6=-sxCpd(Yk;=t*<9WjWBP z!#yfRw*`&M2E~{moUrF3%YeCc;@RcaiJ^?#jBX%t*dPaSN9}5kf^N#3bk4}G0u5y8 zFfTKX0hdNCnak7+f=j@#mbsXM`}xm*-ai|yF!r=RTh`V?xAeZsbA$srWhQu8C&!c5 zP4nVzL^Y<{>?z9$dp^~n7?&Tx;Byf69EV-doDXZY#&q*|6ee%>&*8vyOwp&{=uWorNMrSdR!pXA6Q3{83aF?}qd40>&o~*l{7k6IZ-Nu^~M5|T_>R@Q` z{B+&e8*+y_{b29T5tczRR9P1^qak>Ns(>bovvp6<>`tL)=GDSz-42W?2)iw_Pi!OT z5ckrv?U`j^4YbX>c`dbFCbbvV^WAMH&o&;`*~80vzPR)5p17OZTii=Harl8wpSg6m8N|=o$KYD9z$ou) z`Ma>jU5j=lxNY^yWbKvRxAtk=J)3Wnf+r26#^P<%xMkg^I?gR0X@@?`=;JjwslZzQ z!#ecUdKxN-m)#rLz|9ot$?nvQIeYESz8E@aNw+*(uVTd8^wEJK*Cy+k)ccqA&D73Y zyR6~vD;w*6@seZt!4ukiYu7On#VhqToQ6C#Ic@imsA0_0{d;%&;PfX>PS8Tg>P;+R zZ4d*7Z0ew&pfk}4$Lh&+;FdNA`l4LqHK4~Q>%6QX{^CW+2`xK$SkJe1vfCc69Q+8D zo!r)u64w0b)>oBYSKOs}+Ni=&W@=maChJ5|+-_yLcAQDv)NM~U{j(|-uiCA~^yHYW zvjHhgYV{&=X5_HE21~-)s9{}L2e)P5ZgFQDpR8wU8!)HwzO|ju0($EP+?-UR=Qfsx z%vfYOaoMK~c%oZxwLfF)Lwt*$S)T!|ZbS(rs%A8U!!56ur0!^)eHzn~6V5D7>SpD5}da};8nJ7G)G2>Xr&zNPca~H#j5b6md&eX_d8!6nq6zdd?@l9K$Zop!-BhmXXJ3{ zIPPYLUtDt82N}n_T3GWZ%FpjDCvi!KwI6NRpZmT}YIhr#+Bu;izHH;mkHebR^R0c6 z*+<{nQ8Fs=e+kXy416og!InO9@NOI1Z7ZpHBjyAR(|(ce-qa}<3AFnOZ&t7V4WZ-D z(K?8`2UELG#pq};CgOVNmSO2{M@>OIB_48*fs5Rfs!+lT@t5|c#OF5N&)UaQ`!cxA zt2D1UIdLzcxm;o|snbTDI?-ntb~`U6>li1MfR6uIQ*XYZwCj^cJZr$#fwCXt<~SO$ zc78kPsw~`^eqFC~? zh8BC_QeLMGPaW&947i<m%<2AL!1teEJQtob?Ji*M7z&SiF6 zv=ZD&?d+@Oio-Tu844nrd0&5dUy|UjUus{TwO}WjV+1eXK1Z8M#-2(}OdKw2>V@@w z-+J{|HM)lLRF+EWw0Jxt*PV!#?h{p*LK>lhPCIkEJZ%cK^?q^ z53)vld21g`ZOh3-iiwiiSy!fu8l8?HDWcxuZY+&1#-y{zatD_kZJEX87BmfKO2&D* zNtuMEZg#u7=Xvw+=~*Kvp{zsJiAUI+59{q)yG}CdXZ2wuqi0QdY1`Cx8T~81%Y5w0 zQ5;-p{gr)TWECJ4_PP6LcFW4{Bw^N|j|ka97E> z_lDPmWyLC_o2ebv0j=I=^Q%=x=pxrMi{I@18E8^_o8VSyp-*q8tGso~`1#V~;47O; z=9P)r#&bM_TROM6%<-(J@qY5kQT)Vdd@DucHFXrICfSY>!VD^QIjTHn>vrf8rJ;gfG?O}RnA(}mdXTEpHamF`H>s_G zBz3L~DffIiKdJ`?vr*3IrXsphlN6)U3f zl0M49TF=B);u)c=cNq5HsPs>Y93u|mgg%M0d&}c&vSS^WGDShh6Mjm@ytVVa3fw7h zGnS;@?%qx6{j$3G3o21V9f=a@UbENySd$yH-D*CG+!9~YJWuuVpfN|@&O6`Qd<*Wl zErjAubP<+4wbj{EkvDY*DQ=JGhEZ`dCh^$YOfUW1f;fi94GwpmX>yr83Twg0Ry)GgWRGa_X`gI7{JJ2}dVjJ{=3 zTO_sx<#bYa>Pk@^e&1L_AD8OkmQ+^nWX&$?K9~ig&IszV4iWpXKQ0~Itta=`&3BjV z)NSm8MvEJZ+WZle)y@<1HnknV;I^3uw0gd&w@IC|Us&%x)QvyTmw64oOr5|ZNK{oX z$u;wCNy%fExBJNKzsz2*;^brvRzL@q7?amiWc`=uGD62mY8!zM{tkrx>G&GKhiQ#K zcbUfC(vqjt?6}v2iYJkmZl=pV-_(X1>z1%S_?fz(%i0#92s|aSY*|MNbyQuXb~!;D zgS)ifU7IeiS6%55e4_+ zaO91cwDM+`_!@bOSKivN;+vAsS!x;Gq|WCob>Gy@=*xhP6!C-zi^%b<;1-}KF8hcP zPIQ~M`Uqp|Mo95ltGP(V|3zZVq0%{)(yv+-+T=tQZ7qn}G2}A+FTbEhl!D z{KrUYmvu9GN$Txq>Y3CQOx|BrV+)!yLXMJC+t^e5`gu#EPj!%6K9UZ7Fybu!#K{6G zCP68QF{!Oqval0iV>F0im!Sxr5u_VTVBM1Mu|7M}`=s`_2pVdufGL!m;TasWGEtM- zGB>F$yOo1Uee6xW98{u4(jh`k&=FzEJC(mAEZzE4hthHfk7t|?5`&Y(Nl6F^N8R;| z@;0vn*C5mAIAyH^KuY%E5D&g>ou1oTM*F)Wu~xEC3m;Z?N(&usbdVawJz4J(dtc~w znzeCeyzDM}&$7LO!P*kkl6Lhpa+w<9mi#@^wsCEyn{PgMxKZ8`flZ-qCqY zm$js}+bj7@jq( z8}S8nlY05`WZAtFwK}*b>w^kRYV1p5nom_s#yw}v=ir;H6Ju}#t+0bnXOAe;tJ>P< zIK&T1m{Ll%Mu9T6C4cKL*8UP;Hp<2XI*3C#puHnp(ubdrf#`sZDbOjnD_WE#sk4DE zpc8&5t0(A)(5P!nYIgwI;~k1|yR1*A_8!`6-r5a~Vq4Y;xsk@1>7D`IC5xU$@M2A3 z0$sRiNj>30nal7k<$%s#`wT1A0nJwCCpEUkV0MeMtdYffg4WW{S-JszjI|JyXfjzx zw;6csyJWo#_EbC$Gc0k(PB0-gX?1>uI}2Eube^_GCJ3a9w8Kmd*;$ ziog8ZnhEQLa*ltFd{Ukdrk13(arukv0=mcVWdnB}%aJVmn2D;ru z6_ui$fM&-_w#r{*6~t3=*&|sp+WUPAI`O`)peO6OY$D@SSkKFsg~%K^s}z@owJ^n7 z+=*QuJv~xS_|U=QWO3_EeALRcMo<=Lu(nPjCzpZlKi9(E@7%k8q9Wx2^6tNO54FVS z0B`%&F7bj6>)qZxegiy7-FTbSk)?|~a!mm%#T}>NGFqpou$Kotad`aT$i^>gMnG>_ zH{=EwH|mx4xS9cNs>Qk`Tc*=mWlQ(xW@aLacmG!AfHs>L-U`AMd)JD-mR_@I|^row`z7#^{5~fYH{BX>T{iWrj_k`4oFQMItKh1dHzp))`syGM4dO zCIzG(YDwYHbQ#1r2B^A4qtbt0Nj8UaYVApCOQ`3)7~T;I+)ZsEB((##thY(6+YIwx zJgLhXrYY>}hZ}ctHM^I*jvHnV>l)KHeJEd!F+wx7mPr=Md6|8?tgl|Z$_CW>nV|9Q zxz62u_~Hh|5R|!r8`ik*6Z&vcC&p$p1(E_&{G`bYlYM6tGE{5Xv7PSqn8=Ks=va0~ zgk=xMI>n1JMgupdPf4;E#0fe~Csr*j5VI%fYy0x(z8Ed6Ay&X$4g*r&35^fJ;c#$6 z8{$ps?e3jbJwb?Aww$#>dV1FZn9xHKT32U*K{?b*i7E-21Bq)psdPtfirx&*joZIDGPmz9xm z8QIfkJ~hYOioZ6=D3`VEn!M^3m+s24um&-#C(YQhwT<1hlhL6pqk(>SUyO!z zL4zC6**&}|vW@4%mxy?t)K)j6v39B4GO3NQ2vy}7cgA`SX#A9^yq4LA-AQk2#yi7( zj5V@U-IfrCTZ*Az6E4jf!8&W*f|!Bw1da7W`=W!58sdd=SgYOj(aZ@gshx$2sRC{( z2eih7rkl0hazWsz=C2=UJ{+9=&T#iB##}$0!WwJTj1zfH&w_U9W~XL!8OXt~o>*f~ zxa^ia=bQi5e3Ck><#;x2DV$QuF{}aGxDy%&ENrn%+#$XLe^J~`X~;>js4?}q=lPW> zW=6*cEpEN8Qycu?>=$C}R({;DNV)SGgd3^S=vdF-C;cQ}CH1x3!n{!8uxIxg=}PcAPt# z-Q!yawzEf&faav97S@EdZO*dez5fT)9M4e3G4-TevNeJ@^`tDRfxiF#`yY7V0poZ_ z9|WBvft8RC+E{ZHKK}1fzlL>M7S@S<3;K?w#)S_l$D}qXCtKpf>>T@Im^(ZtczhXC zn3-!jKoFkP2T$FSb-2Ur?dcs2-%R0TZtEBYy-VgtUOkLu>jqi@8gAVVvIaVbfw0bp zFH#GT^AmR{s~6CXam%_oGwv*{wmKh^n$BAXJbq_B%%|AXjm#3PU1`xOQe@Jw&Py3q zOlMNFoytoq@KBcT3fxkDp3npsRTEC2 zhq8Lcn5flLkl0hPd&1hVoo@QTrL=ExPaoKqcVj-dgmw(~!aAT!`GW0D#3(DSC0c=o zZ^))mjcn>5R&OaMsqee*J_fkKokR|0b+!(7o!@NZrp^g%3VV=pLW{_Y8ZM_+_e$hr zpzStsX3Ki<(NA&>rl73{!N{I%5&$<)WpY+;eB9 z8}Y;xO8sHPC5<{*QI0)j4fMhn;ud$wZubt^#*W=u8M<~qo_ za2>|jtrxMSt zWlurwQrkQ}2h3cVdOCBA^*!;20u5w36T9KNoSL}wlw`>#>m0)Zx_rGW6;h{W$ic~) zEo}=omq}zbxZSkDRZ98)-xn=5in(uxvPLfpwduS#!kVAOouDWzB6i{u(G1q*ER~2s zu}hZu)EteSxlDZ!v`_wNk8cMZn}c7{pLFYki%Z+f%&Xla)XN@T)*Vq-tDk<_E}Fu2Fb?aI zEod#1Z|&rASpyx`!R>L$3vqI}pkqk+9M5=VHCmQfb336WkcM+CUhNg<-hxif7WV|* zymmL;ihJ?%E`7`6%b43sfs=0LHAzuUK{gp3(7v%$u$GB9hV?D0^=*^0BKqyBI;dN4-0J&5~SB9m=V-Na4A47c>Lw9L1B@eP#2! zQ5-ZH{xmMHq@I0n89%&=uRs~cSi9B!9$yA@*|{$7VISEV+wn6+S$i8!)~~*#Fa9{K zbXI^?aG8k9S0fwWEo<9#DQD{j`v2P(hF5=BmvWN2tgSIC&`~_B=Qh5LYa4r7E-&K* z?b&6DW2}4pme-P6$=4}e3@30;pKr_0be@k-dwQ;&ZeH0m%-Jk^ctJ~Qa0A+VQ(-$V z*}BWLe3vW+H+&0srgK35zx!g5*u%qj)@98NtaCieD?1S_vCJ@Q-=%bOir83}S~!++ z^BQPBVbA65vgY|+`rO!K#BKJH*LhR-HJukUzBW?DAzbm9H>`tuB4!71YLrtZYl(Q^+DE2 z?XXra&;zYumWdW?nu%sc`%Txbfjda;yN_k7&yv^9X5NhU@UYICT1Mlm0G)zM zSOeNz4&N=}q;?KtGoyhH>;L#4|D!>S32rE-mg%N$UOR_}b&h9CEcaZTgP@bw1A*ZZw~P>SS5zB+Rb&u1>I^O?G!vvr3u{ZkyjLpe2w-L8xEAX!i;#Pqw1=1V!JzJ@u^YwRgAVK9o_P)WWPM^M zzneggJ=<-Zl6hZmSqF4K1xvsl#q;7mQCkd4$v&Uj3b7>ESO;_rX>KQREDURoHLopB zJ|7F`j@t{Gagg=0d!yF0&F-C#S}3QuY-&&38AqL$!ZO!%BeA6Aj^mmS&TU-o$RK%? zkJY5k299z{->Ts?&;I7Dv_#u+r8=$!x zBZy|p?t|9&b7yV0Bu=nCk=m0ods4eIyR2=GN$qUo*~7bm6F;xi@G78*?=eCQ!O8#pHe`W~isDaSa-y2)79+oYDrIhDz4f56bCf_QqKz`e}4_>)U; z8Fz-bPc5vI+QIEyH1iq)G#A!jO^BDV%eO{BGfd%?(Gz%H);93hgY{O`MfMX(9fD2X zC8_-(aV@>O;O@%F_{*d&w~m$9-56mlS)`0jlB#)Y!)^bBo9s>Mur8x%+$CiPfPl{K z?e$@HpnZ#ym-Rhoz1368B70aA&E=C?UWa~gFRYEzF^}PnCkLIpd)!znB+Y@G$o9{C zbtb!m8_@DiGWN2@7J6^h$g`~j+Jgmc-t6A<1kOEcQn5ajI|%upbX&wF4n(08wB0!D z)KF%x?(UrpTwZI*Eq&Vm*iPOV4;lyEzJu^RLbqrb)>6BNwBYvM3~qUiR~gkP#2O*q z%Nl(o2FeOMTen$cbdF@%z2^!1Zdf0b>jY(*A57{k=;W_D$M5{L5BUoLH0G6E+>>>) zI}@o7f==T>|L+EOzZ*|>=c|=`uVORzY1fg-TN}rcTG*B8Vl3T)IJKTY8@ZsH)Z5)V zYjU5~m(A;gDxIc$3^Y1roy{4_uny=Xb?w}mxKFbV^w*pCOzmX%#NF)9&$&W8Ii9SX zC>P2u=UsL|hq8U!VXUD0nzqt%B%5#Q+ugtqf<7T;DbJ+t?!9G==G?tY8Q<8KOl@z9 zX7}j?=ixS}+e+|-b#coqCGYN;;Lsor6XMyf7oZ0(Ls@@M`2^>2gE;$HLiUZMv#r~) z(4^iY%klemlX|PkV#GCq9Qird*R>hXJ_7jJ+O!v<~JiB7w+E@p7-`%ndaUc-) zKFyYnI8ymmEuY8&u?rx}AaHX_H~oXyv)<101w9Ym6EtVy+p)Zcb*}B(rF<}*BmOq2 z16rL8yt!PsHfjUrQr6GZ4(??q&lFu+3-r_La~o+|rW#v&;wI^y_U==dEmSG=eDqF^ zgRX#;y&ZZ5$E6f*IwXtptUBpzSj$O~&Y3aalEsY$G*|0?Lpv7r39V)l%|zZ(UUqMk z1A5uOHOgEwayZ8`#OHzh1nU#T4H#FC#d0wAO0+c=*2SF!4{pS>r9&eJy~jaMflLWO zSwBm$#?Z|pc{Yih578)J5_DOMF@YQm_LwqhpP-kVnz>v%r?MusY*i-ffHo}mOfgyO z>299wHhwU>PY^fqiHHs=P<*48dnR~t9CT?26Yee8DL5`A?XC6q;69Ic zf09Vaj-8B7E~}>}b&tXG8O6acPsnn+lEMUMcVeVyFc)Z~cY#K>H`!frfiIq2<{unA9Dgkx2`>#`LyVJao>~_pP_;@=n(;ai~1n5#`Owg0;w2x6P z>kv@`sxSiD_+kNC%h$g4HK-X$aE6GE;YMGF3yPVT8+`^R8Mz1DA}}%~``*@Q5!E ztN|;51BP{L$?jZc%uJz9sSk{L2=|tFpdUm}qN;IBuCz~uUstko@JzY|eZtil4ttVi zR|>`~(XBF0#GxF`0aAh^Xj}#~m$EzgrwU$p;e}?jFUc$o-xb|=-~G;Ma$Gl#oxpA6 zOtGJBS6wiF^}Cmacmg@beJW6KVw{lCt%Z15OhEU0O zuI7_+i0EkqUIn6m9?q%zx#ynK-mTl0NcZ3G@11z~o8SDV&tK{35f2*KIQcB5RFyMteNW&ngDg|Hyrow&gc)6eJ;-{Ii-0LrHIx^` z0pXU;hUJ)4<-adX(EQSuzNFE1t(yn;pzrsy9{(<+1Nnb9 zjMMeT$RfOO_9k?rDceZXGBt@k6+12O7RSQt4lcK2-jeckcnRlN)C8H7D_S&EPhsi2 zDDSeMxfg1_0?ijDL7xmApg;DDU;Ki5R>HTx{q4_w_Ol+e9)jD9#th|MZtu%7Y1Z3x z%v1H8(TMiIFH3x?$38*)AeuWs?2&^*otWCK#m@=)1my{OY8B8^%*eZF?ov;}nu6QD zFJgS|bDsk`1T}hPOHltxuy^!>4?gtqkMBVL(?9)_bQY%0-}%mWn*Lghz!TG5aK8E9 zW%jtF=4Tw9#EYA8XT(nnevr}a;@%E&deQ~-q|81DIasL@aD{GlhmX5*i44rr`pF5Jo|KJf|J?L(Q-^7`iXg4=?bnZ7s^ z+;>TwP>Xa+`W&OM<&~C&dmE4SKQ{hpzQ+&?XQ7N#K{quf#^-FMjb$lv6(W$xnJj;P`sP%l#YQ_=bNbGNT!mt2{BI#0FYt zg`p(Xr!(vlkN*j$(RE?RF!;eNI8FQnj)Mdj+%6AxJ2C9C-j>yPFa)73!B&K55`9W} zkbcwHVwK+{^472<{N?&c3+HH^pd)OWjBrQv^;b2j$YZs2a^VR$~k3AV-ZM ze(dgcoVHBRi$BNQ7SW7x#y&wurA4~rR6$2Zqj5tBa?s#7+PD4aiUSxKKk4arsqVY) zjsC&OFMa9DfB*M?KS8to#+{$!Vr`vx#8AR9l>OX`K#QR?nuu-QncaaNuhfgrF0*J$ z+z7KwHFms@5MShVS@DZwYaC;`ZQnlImQKW2+&Dp5APsHC%buXgvQ>9qMsH*H1)8xx@rjQcKWd>JzyAS0e77h6 z!$17P7POYM;~tdyc?7Orz538Y z4_X*b>E7T52iIJm{`99!VJ-2h3C<191UDxyNj&Shftw;~M48JIpU?{>#w{V9=rD)6 z4B~L#x}9(mT7ymO2PqSF7LORg;8h#b7hZV5nHd_5ig6sW5P$She~+KP2mA4lfBX|a z``J%VfX=Po{N^`4T;uDvWgmIu5x-?;YQq|kG6sYaYny{l>nQJMdxkQ?%tGDb?kY9Z z43J&o(SatBB@(F@^~@MmmwMuum`>0pvqw2~gQmCc@N*U6nj* zipWl9k2`=lhDmDUB>Uj78TkFUM;>|9pFG3M$?7-1`Ry%1r-L0{`ak>ZvwrQ$EB^ZR z>!w5B>p)O&3m<5>LAT5(qtSlIG463=!JSM`6j`))L!1vvb*?d?uqUq*SeIM#sX1V0 zS&TR{LEkauC=<|@hmko0F>Ouied@fVF!-!pAD@f8N&Nn^*Dg{J*meK$AOG=^pxf>H z-~WN1Z}a^6^~WT*qa9?(!j!of-r#v_;2W>p;utrwTtm6_3EcV{WViJ9CAlzlV^2vV z@}m5t6MM2-ur8Og=Q7SROD-=%SriFJXabxC)2T*NK!1^P1~`;CNj*ACXK!b>=*$7n zNSGh^CYK1p7;zdeD1|V zJ&zIR{9MCR0h%b$N4+IJakC@)QZJ+?MD~K%<P#3Y07ZK?M5M@8DnB!KuyJm;pU!k3VXDrjEA(-Ed-rZz;!cOJ^Z)BYPwDOyMo*BUO@!!*n(~%AmjJJ@3AD z?V7jqV~;)N+3$Y$yLUkL*dssx`OjZ`@g*lTKNp(`Zr>1K$nxCh`h1Hn_vx0!DTETo zl&iBe@GWj4AYSN#qGu$n!i*|^kT`u7f+bsH>99p?WTg`^rUUFa#={goFO)^MM5;xf zgkwet8@Y^ThxA^~%h4su?&?fcm(uy+hy9fT5Bp;cU;N@1e)-FrUvVG9cf0MrWc&X2 zzyI8GU*XvG>yKTz@~A(Y%2f`CLL*l#zmI(6qc$AGad%7me2;TAI(TFfXD?DLT9tTI zjYLLMCIU7nCf$|=Xh1KG+o!ZFlo!zP=K}JnkIY%jK`a~(8krlRtQHH(_C}PQv?-7z z(o;Hn#2*6osmi|XFWfbw*Q;Ikb~#?Y|IdE*vu}Otn_RM}9Q+&%e1(n_tb8M#MTodd zNAwW48we_HyG1>6aaDhTPvQ&i$TFc<(kQIn(_V=m!)@vXZZ8i~j;qUB>WuXvUS$nW zZ}~5x8I-#^8-a(UNEV=MC|_L2Wgl%OW!*du^fS-A*LHpX{SQ3)=%aqAK%dtmowv)t z2XF}vC071O;>^bL4}bWtL)=>Bj}S^+XGb_OCOWnL0?`uUA}aKqIv;xV`_(P( zCU_K%;L(49a!KOHD0_SvFteyLX%`-2B2GjL=ukGG>5|CV2DN)Hqbx6cE_Ruu&@+PQ z?<;GsX2l;ZbR2s5(uc8QSBd2hEj4w(p7ErEI01(^qrZ zErr7raMxOU`sug&-0X*v{tA3&gco1@)^C4%*)K`%73hxRJ5>io`;WhJ^~#k;5r6W@ z9dTd0^s6?TyhP@_&jsQVoh?Yp3rf_YQ`15C7ISliRx`V!p_VCZaeGP$bTw_4lr)!e z3~t)fXL+!E4VziiTg20=*m1*{c_Z&J?%r-5_Zik<#!H!WaO>}`osb(SQ-%-zWWVn; z{EorZtJmxUr1SQy?Eg|m&TMueKNs`IlplV0_jfP*ldV+x$VdL#L0v4_)iI@#AD!qd zQX9K8hfj>z+jS6^OA>jUEYU5XC;haij`9H!+@5Wj>_RhSXT7D|#~G7yU78Nm4R`aP z!C{?ywRY>@SCNg~nMY&R00-y*v<2ml|6aNB=pX*!8`bjQ^Pm5MZ%AI(GuZ8}9D9qe zRlo6#Z-~ebMz37i5trk3cu^pZ6a|vV3|VijTG)y&h3pJl=vIiHU`6f9YpB{an&ZK( zj_j$A5x*tnj0R#>l-i7)D+|mN#^)-BAr@l_+byyC1%T(De_o{Y@kIotZb@V-T!%g7 z-GcYIhHm~T8I<4ku6Ij>AO7%%|IDxE%X3eT+o0^&`)}j@8yS!Iizx&}B8|cnok*=` zjg+*!^^Xpq3y?V4Bbsh>lOW*^jmH%oqJLS(i1@8TDvziq@oBe1jXaoHj25Gp8HzKG z@sn@7)yNr#C|K=XLi5^k?y|fA%`(u(XejIH-x1BX7WduvMjxrX@;>#cPy7Dr_m*8H`O9DY-QWG)-~R0jqVreR_*~|DyvHBEVRv%CfLjqGwc*Z*U8aDJwJnY^vcPud zy`~#|bR!WZm7up0$mQ0gPra4^%4G@0n3Q8L9k!RcnJcAmd9K7IjpnjStyNLTUx>v5 zaXx^=e{Smrv0@fqfBA9q0}niuUkP(p)F}I;Q$7Dx7##lTPk#y=WIkivxbcJ|rFH8Q zgp-K840KRvNHMy}Uzak%;jNpVZ)PNjM*ZnSRl4nEzA3fEKq$Ae04}h+`o*>Npv=bF zi{bH>Ff}Z%ve+`|Zoysr-kqiBD1|SkK4svm$Yl=ah!t0jzyX~<^r64tVB|2y_2SDiq9`qQ6$|NGyQq%xEU(%jc>z6G+0fleGbODKh;gheN^ zTL6-sCeClRI4^hN*d*0T=*uH_llvBrp)8f;GKH0}Hp?ts06KI}@GJ+i0-ZDAv$Svw zS=$t{YE$#XCng=NRnr-S!wSP7Mo<`n_0uAU7I5$1|8|fsptNVZ{^c)Uxq}}!UsCpe z!ES>3^{;>J6GXlv@`ZtaHsQt|y7T8_k3IJE({FV$0a`9NYeS4!NQDtQcO^BlvR-~! zKhg^QAV9(X4~=3^un!;wiuItsluTiRsL?GQ^wi&jy9KmAGhpi5042kk#ay11*Lj=B zUmT}n2=biUoCMt(c1p3NA9&yawY{4EpZSd6@p#GG?O*kFefd@7)8hVXw;#Ol!q-Xd zph6kH^5hg}@n5~_AC-QST#$DTUj$5%r{pDXcZMJBa2E0-2ylL-LVmIZ_oGo z!w*05;Dfurwb&6Y6(?%iuUVW?id%k|W)FivDPreh-_viB6KJQFL*uVO#56M4AyQY|JKlB;6 zq`=|Q25XV{mAP45=6_i~9UkuC1Hlkpva_QFt^h96E`>^0u&Kdi&-~W-nXTJAv zImve~cUz(ptnVCNdgYzV|!z`H|hHKmD0!pZ$`LdVUqe_gZ`amp@kH zIe+gV<%2^(PiI@DW3AI2`rrTl57e?uuD$TW?sK<8wL0IuSPU`|wU2)EBi;y#?=$!1 zqdr7`@{^x(Zr}HR-m{9=hs{L78WUNwgsgeba1Rps=WK)^+rB;Dk9yVCfNv^t-t#84 z43zJE&;MR6`^)dC-GvoR#n$1)q0WHD{O63~JlEwF00<@pwQR6jT4ZI44MEW%moZ>f zbau<*?90!4?s-<=tiV};vjS%Y&I+6rI4f{g;H + + + + CFBundleIconFile + casinocoin.icns + CFBundlePackageType + APPL + CFBundleGetInfoString + $VERSION, Copyright © 2009-$YEAR The Bitcoin developers + CFBundleShortVersionString + $VERSION + CFBundleVersion + $VERSION + CFBundleSignature + ???? + CFBundleExecutable + CasinoCoin-Qt + CFBundleIdentifier + org.casinocoin.CasinoCoin-Qt + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + org.casinocoin.CasinoCoinPayment + CFBundleURLSchemes + + casinocoin + + + + NSHighResolutionCapable + + + diff --git a/share/qt/clean_mac_info_plist.py b/share/qt/clean_mac_info_plist.py new file mode 100644 index 0000000..75e4f43 --- /dev/null +++ b/share/qt/clean_mac_info_plist.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Jonas Schnelli, 2013 +# make sure the CasinoCoin-Qt.app contains the right plist (including the right version) +# fix made because of serval bugs in Qt mac deployment (https://bugreports.qt-project.org/browse/QTBUG-21267) + +from string import Template +from datetime import date + +bitcoinDir = "./"; + +inFile = bitcoinDir+"/share/qt/Info.plist" +outFile = "CasinoCoin-Qt.app/Contents/Info.plist" +version = "unknown"; + +fileForGrabbingVersion = bitcoinDir+"bitcoin-qt.pro" +for line in open(fileForGrabbingVersion): + lineArr = line.replace(" ", "").split("="); + if lineArr[0].startswith("VERSION"): + version = lineArr[1].replace("\n", ""); + +fIn = open(inFile, "r") +fileContent = fIn.read() +s = Template(fileContent) +newFileContent = s.substitute(VERSION=version,YEAR=date.today().year) + +fOut = open(outFile, "w"); +fOut.write(newFileContent); + +print "Info.plist fresh created" diff --git a/share/setup.nsi b/share/setup.nsi index 2280a6c..5f3e606 100644 --- a/share/setup.nsi +++ b/share/setup.nsi @@ -5,7 +5,7 @@ SetCompressor /SOLID lzma # General Symbol Definitions !define REGKEY "SOFTWARE\$(^Name)" -!define VERSION 1.0.0.4 +!define VERSION 1.1.0.0 !define COMPANY "CasinoCoin project" !define URL http://www.casinocoin.org/ @@ -45,13 +45,13 @@ Var StartMenuGroup !insertmacro MUI_LANGUAGE English # Installer attributes -OutFile casinocoin-1.0.0.4-win32-setup.exe +OutFile casinocoin-1.1.0.0-win32-setup.exe InstallDir $PROGRAMFILES\CasinoCoin CRCCheck on XPStyle on BrandingText " " ShowInstDetails show -VIProductVersion 1.0.0.4 +VIProductVersion 1.1.0.0 VIAddVersionKey ProductName CasinoCoin VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey CompanyName "${COMPANY}" @@ -67,7 +67,7 @@ Section -Main SEC0000 SetOutPath $INSTDIR SetOverwrite on File ../release/casinocoin-qt.exe - File /oname=license.txt ../COPYING + File /oname=COPYING.txt ../COPYING File /oname=readme.txt ../doc/README_windows.txt SetOutPath $INSTDIR\daemon File ../src/casinocoind.exe @@ -99,9 +99,9 @@ Section -post SEC0001 WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 WriteRegStr HKCR "casinocoin" "URL Protocol" "" - WriteRegStr HKCR "casinocoin" "" "URL:Bitcoin" + WriteRegStr HKCR "casinocoin" "" "URL:CasinoCoin" WriteRegStr HKCR "casinocoin\DefaultIcon" "" $INSTDIR\casinocoin-qt.exe - WriteRegStr HKCR "casinocoin\shell\open\command" "" '"$INSTDIR\casinocoin-qt.exe" "$$1"' + WriteRegStr HKCR "casinocoin\shell\open\command" "" '"$INSTDIR\casinocoin-qt.exe" "%1"' SectionEnd # Macro for selecting uninstaller sections @@ -120,7 +120,7 @@ done${UNSECTION_ID}: # Uninstaller sections Section /o -un.Main UNSEC0000 Delete /REBOOTOK $INSTDIR\casinocoin-qt.exe - Delete /REBOOTOK $INSTDIR\license.txt + Delete /REBOOTOK $INSTDIR\COPYING.txt Delete /REBOOTOK $INSTDIR\readme.txt RMDir /r /REBOOTOK $INSTDIR\daemon RMDir /r /REBOOTOK $INSTDIR\src diff --git a/src/addrman.cpp b/src/addrman.cpp index acd0d46..780edde 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "addrman.h" +#include "hash.h" using namespace std; @@ -187,7 +188,7 @@ int CAddrMan::ShrinkNew(int nUBucket) } assert(mapInfo.count(nOldest) == 1); CAddrInfo &info = mapInfo[nOldest]; - if (--info.nRefCount == 0) + if (--info.nRefCount == 0) { SwapRandom(info.nRandomPos, vRandom.size()-1); vRandom.pop_back(); @@ -241,7 +242,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin) infoOld.nRefCount = 1; // do not update nTried, as we are going to move something else there immediately - // check whether there is place in that one, + // check whether there is place in that one, if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) { // if so, move it back there @@ -410,7 +411,7 @@ CAddress CAddrMan::Select_(int nUnkBias) fChanceFactor *= 1.2; } } else { - // use an new node + // use a new node double fChanceFactor = 1.0; while(1) { diff --git a/src/addrman.h b/src/addrman.h index 0392654..7af6afd 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -117,7 +117,7 @@ public: // * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not // be observable by adversaries. // * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive) -// consistency checks for the entire datastructure. +// consistency checks for the entire data structure. // total number of buckets for tried addresses #define ADDRMAN_TRIED_BUCKET_COUNT 64 @@ -174,13 +174,13 @@ private: // last used nId int nIdCount; - // table with information about all nId's + // table with information about all nIds std::map mapInfo; // find an nId based on its network address std::map mapAddr; - // randomly-ordered vector of all nId's + // randomly-ordered vector of all nIds std::vector vRandom; // number of "tried" entries @@ -214,7 +214,7 @@ protected: // This is the only place where actual deletes occur. // They are never deleted while in the "tried" table, only possibly evicted back to the "new" table. int ShrinkNew(int nUBucket); - + // Move an entry from the "new" table(s) to the "tried" table // @pre vvUnkown[nOrigin].count(nId) != 0 void MakeTried(CAddrInfo& info, int nId, int nOrigin); @@ -253,8 +253,8 @@ public: // * nNew // * nTried // * number of "new" buckets - // * all nNew addrinfo's in vvNew - // * all nTried addrinfo's in vvTried + // * all nNew addrinfos in vvNew + // * all nTried addrinfos in vvTried // * for each bucket: // * number of elements // * for each element: index diff --git a/src/alert.cpp b/src/alert.cpp new file mode 100644 index 0000000..adf5f8b --- /dev/null +++ b/src/alert.cpp @@ -0,0 +1,258 @@ +// +// Alert system +// + +#include +#include +#include +#include +#include + +#include "alert.h" +#include "key.h" +#include "net.h" +#include "sync.h" +#include "ui_interface.h" + +using namespace std; + +map mapAlerts; +CCriticalSection cs_mapAlerts; + +static const char* pszMainKey = "040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"; +static const char* pszTestKey = "04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"; + +void CUnsignedAlert::SetNull() +{ + nVersion = 1; + nRelayUntil = 0; + nExpiration = 0; + nID = 0; + nCancel = 0; + setCancel.clear(); + nMinVer = 0; + nMaxVer = 0; + setSubVer.clear(); + nPriority = 0; + + strComment.clear(); + strStatusBar.clear(); + strReserved.clear(); +} + +std::string CUnsignedAlert::ToString() const +{ + std::string strSetCancel; + BOOST_FOREACH(int n, setCancel) + strSetCancel += strprintf("%d ", n); + std::string strSetSubVer; + BOOST_FOREACH(std::string str, setSubVer) + strSetSubVer += "\"" + str + "\" "; + return strprintf( + "CAlert(\n" + " nVersion = %d\n" + " nRelayUntil = %"PRI64d"\n" + " nExpiration = %"PRI64d"\n" + " nID = %d\n" + " nCancel = %d\n" + " setCancel = %s\n" + " nMinVer = %d\n" + " nMaxVer = %d\n" + " setSubVer = %s\n" + " nPriority = %d\n" + " strComment = \"%s\"\n" + " strStatusBar = \"%s\"\n" + ")\n", + nVersion, + nRelayUntil, + nExpiration, + nID, + nCancel, + strSetCancel.c_str(), + nMinVer, + nMaxVer, + strSetSubVer.c_str(), + nPriority, + strComment.c_str(), + strStatusBar.c_str()); +} + +void CUnsignedAlert::print() const +{ + printf("%s", ToString().c_str()); +} + +void CAlert::SetNull() +{ + CUnsignedAlert::SetNull(); + vchMsg.clear(); + vchSig.clear(); +} + +bool CAlert::IsNull() const +{ + return (nExpiration == 0); +} + +uint256 CAlert::GetHash() const +{ + return Hash(this->vchMsg.begin(), this->vchMsg.end()); +} + +bool CAlert::IsInEffect() const +{ + return (GetAdjustedTime() < nExpiration); +} + +bool CAlert::Cancels(const CAlert& alert) const +{ + if (!IsInEffect()) + return false; // this was a no-op before 31403 + return (alert.nID <= nCancel || setCancel.count(alert.nID)); +} + +bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const +{ + // TODO: rework for client-version-embedded-in-strSubVer ? + return (IsInEffect() && + nMinVer <= nVersion && nVersion <= nMaxVer && + (setSubVer.empty() || setSubVer.count(strSubVerIn))); +} + +bool CAlert::AppliesToMe() const +{ + return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); +} + +bool CAlert::RelayTo(CNode* pnode) const +{ + if (!IsInEffect()) + return false; + // returns true if wasn't already contained in the set + if (pnode->setKnown.insert(GetHash()).second) + { + if (AppliesTo(pnode->nVersion, pnode->strSubVer) || + AppliesToMe() || + GetAdjustedTime() < nRelayUntil) + { + pnode->PushMessage("alert", *this); + return true; + } + } + return false; +} + +bool CAlert::CheckSignature() const +{ + CPubKey key(ParseHex(fTestNet ? pszTestKey : pszMainKey)); + if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) + return error("CAlert::CheckSignature() : verify signature failed"); + + // Now unserialize the data + CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); + sMsg >> *(CUnsignedAlert*)this; + return true; +} + +CAlert CAlert::getAlertByHash(const uint256 &hash) +{ + CAlert retval; + { + LOCK(cs_mapAlerts); + map::iterator mi = mapAlerts.find(hash); + if(mi != mapAlerts.end()) + retval = mi->second; + } + return retval; +} + +bool CAlert::ProcessAlert(bool fThread) +{ + if (!CheckSignature()) + return false; + if (!IsInEffect()) + return false; + + // alert.nID=max is reserved for if the alert key is + // compromised. It must have a pre-defined message, + // must never expire, must apply to all versions, + // and must cancel all previous + // alerts or it will be ignored (so an attacker can't + // send an "everything is OK, don't panic" version that + // cannot be overridden): + int maxInt = std::numeric_limits::max(); + if (nID == maxInt) + { + if (!( + nExpiration == maxInt && + nCancel == (maxInt-1) && + nMinVer == 0 && + nMaxVer == maxInt && + setSubVer.empty() && + nPriority == maxInt && + strStatusBar == "URGENT: Alert key compromised, upgrade required" + )) + return false; + } + + { + LOCK(cs_mapAlerts); + // Cancel previous alerts + for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) + { + const CAlert& alert = (*mi).second; + if (Cancels(alert)) + { + printf("cancelling alert %d\n", alert.nID); + uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); + mapAlerts.erase(mi++); + } + else if (!alert.IsInEffect()) + { + printf("expiring alert %d\n", alert.nID); + uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); + mapAlerts.erase(mi++); + } + else + mi++; + } + + // Check if this alert has been cancelled + BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) + { + const CAlert& alert = item.second; + if (alert.Cancels(*this)) + { + printf("alert already cancelled by %d\n", alert.nID); + return false; + } + } + + // Add to mapAlerts + mapAlerts.insert(make_pair(GetHash(), *this)); + // Notify UI and -alertnotify if it applies to me + if(AppliesToMe()) + { + uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); + std::string strCmd = GetArg("-alertnotify", ""); + if (!strCmd.empty()) + { + // Alert text should be plain ascii coming from a trusted source, but to + // be safe we first strip anything not in safeChars, then add single quotes around + // the whole string before passing it to the shell: + std::string singleQuote("'"); + std::string safeStatus = SanitizeString(strStatusBar); + safeStatus = singleQuote+safeStatus+singleQuote; + boost::replace_all(strCmd, "%s", safeStatus); + + if (fThread) + boost::thread t(runCommand, strCmd); // thread runs free + else + runCommand(strCmd); + } + } + } + + printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); + return true; +} diff --git a/src/alert.h b/src/alert.h new file mode 100644 index 0000000..25e140f --- /dev/null +++ b/src/alert.h @@ -0,0 +1,102 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _BITCOINALERT_H_ +#define _BITCOINALERT_H_ 1 + +#include +#include + +#include "uint256.h" +#include "util.h" + +class CNode; + +/** Alerts are for notifying old versions if they become too obsolete and + * need to upgrade. The message is displayed in the status bar. + * Alert messages are broadcast as a vector of signed data. Unserializing may + * not read the entire buffer if the alert is for a newer version, but older + * versions can still relay the original data. + */ +class CUnsignedAlert +{ +public: + int nVersion; + int64 nRelayUntil; // when newer nodes stop relaying to newer nodes + int64 nExpiration; + int nID; + int nCancel; + std::set setCancel; + int nMinVer; // lowest version inclusive + int nMaxVer; // highest version inclusive + std::set setSubVer; // empty matches all + int nPriority; + + // Actions + std::string strComment; + std::string strStatusBar; + std::string strReserved; + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(nRelayUntil); + READWRITE(nExpiration); + READWRITE(nID); + READWRITE(nCancel); + READWRITE(setCancel); + READWRITE(nMinVer); + READWRITE(nMaxVer); + READWRITE(setSubVer); + READWRITE(nPriority); + + READWRITE(strComment); + READWRITE(strStatusBar); + READWRITE(strReserved); + ) + + void SetNull(); + + std::string ToString() const; + void print() const; +}; + +/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ +class CAlert : public CUnsignedAlert +{ +public: + std::vector vchMsg; + std::vector vchSig; + + CAlert() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(vchMsg); + READWRITE(vchSig); + ) + + void SetNull(); + bool IsNull() const; + uint256 GetHash() const; + bool IsInEffect() const; + bool Cancels(const CAlert& alert) const; + bool AppliesTo(int nVersion, std::string strSubVerIn) const; + bool AppliesToMe() const; + bool RelayTo(CNode* pnode) const; + bool CheckSignature() const; + bool ProcessAlert(bool fThread = true); + + /* + * Get copy of (active) alert object by hash. Returns a null alert if it is not found. + */ + static CAlert getAlertByHash(const uint256 &hash); +}; + +#endif diff --git a/src/allocators.h b/src/allocators.h index c82f633..85af8fe 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_ALLOCATORS_H @@ -9,6 +7,9 @@ #include #include +#include +#include +#include // for OPENSSL_cleanse() #ifdef WIN32 #ifdef _WIN32_WINNT @@ -24,23 +25,169 @@ // 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. -#define mlock(p, n) VirtualLock((p), (n)); -#define munlock(p, n) VirtualUnlock((p), (n)); #else #include -#include -/* This comes from limits.h if it's not defined there set a sane default */ -#ifndef PAGESIZE -#include -#define PAGESIZE sysconf(_SC_PAGESIZE) +#include // for PAGESIZE +#include // for sysconf #endif -#define mlock(a,b) \ - mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ - (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) -#define munlock(a,b) \ - munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ - (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) + +/** + * 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 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); + } + + // 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(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(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(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(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 Histogram; + Histogram histogram; +}; + +/** 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; +} + +/** + * 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) + { +#ifdef WIN32 + return VirtualLock(const_cast(addr), len); +#else + return mlock(addr, len) == 0; +#endif + } + /** Unlock memory pages. + * addr and len must be a multiple of the system page size + */ + bool Unlock(const void *addr, size_t len) + { +#ifdef WIN32 + return VirtualUnlock(const_cast(addr), len); +#else + return munlock(addr, len) == 0; +#endif + } +}; + +/** + * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in + * std::allocator templates. + */ +class LockedPageManager: public LockedPageManagerBase +{ +public: + static LockedPageManager instance; // instantiated in util.cpp +private: + LockedPageManager(): + LockedPageManagerBase(GetSystemPageSize()) + {} +}; + +// +// Functions for directly locking/unlocking memory objects. +// Intended for non-dynamically allocated structures. +// +template void LockObject(const T &t) { + LockedPageManager::instance.LockRange((void*)(&t), sizeof(T)); +} + +template void UnlockObject(const T &t) { + OPENSSL_cleanse((void*)(&t), sizeof(T)); + LockedPageManager::instance.UnlockRange((void*)(&t), sizeof(T)); +} // // Allocator that locks its contents from being paged @@ -71,7 +218,7 @@ struct secure_allocator : public std::allocator T *p; p = std::allocator::allocate(n, hint); if (p != NULL) - mlock(p, sizeof(T) * n); + LockedPageManager::instance.LockRange(p, sizeof(T) * n); return p; } @@ -79,8 +226,8 @@ struct secure_allocator : public std::allocator { if (p != NULL) { - memset(p, 0, sizeof(T) * n); - munlock(p, sizeof(T) * n); + OPENSSL_cleanse(p, sizeof(T) * n); + LockedPageManager::instance.UnlockRange(p, sizeof(T) * n); } std::allocator::deallocate(p, n); } @@ -113,7 +260,7 @@ struct zero_after_free_allocator : public std::allocator void deallocate(T* p, std::size_t n) { if (p != NULL) - memset(p, 0, sizeof(T) * n); + OPENSSL_cleanse(p, sizeof(T) * n); std::allocator::deallocate(p, n); } }; diff --git a/src/base58.h b/src/base58.h index fe59cd9..a462f2f 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin Developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,16 +10,18 @@ // could be used to create visually identical looking account numbers. // - A string with non-alphanumeric characters is not as easily accepted as an account number. // - E-mail usually won't line-break if there's no punctuation to break at. -// - Doubleclicking selects the whole number as one word if it's all alphanumeric. +// - Double-clicking selects the whole number as one word if it's all alphanumeric. // #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H #include #include + #include "bignum.h" #include "key.h" #include "script.h" +#include "allocators.h" static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -180,7 +180,8 @@ protected: unsigned char nVersion; // the actually encoded data - std::vector vchData; + typedef std::vector > vector_uchar; + vector_uchar vchData; CBase58Data() { @@ -188,13 +189,6 @@ protected: vchData.clear(); } - ~CBase58Data() - { - // zero the memory, as it may contain sensitive data - if (!vchData.empty()) - memset(&vchData[0], 0, vchData.size()); - } - void SetData(int nVersionIn, const void* pdata, size_t nSize) { nVersion = nVersionIn; @@ -223,7 +217,7 @@ public: vchData.resize(vchTemp.size() - 1); if (!vchData.empty()) memcpy(&vchData[0], &vchTemp[1], vchData.size()); - memset(&vchTemp[0], 0, vchTemp.size()); + OPENSSL_cleanse(&vchTemp[0], vchData.size()); return true; } @@ -410,21 +404,19 @@ public: PRIVKEY_ADDRESS_TEST = CBitcoinAddress::PUBKEY_ADDRESS_TEST + 128, }; - void SetSecret(const CSecret& vchSecret, bool fCompressed) - { - assert(vchSecret.size() == 32); - SetData(fTestNet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, &vchSecret[0], vchSecret.size()); - if (fCompressed) + void SetKey(const CKey& vchSecret) + { + assert(vchSecret.IsValid()); + SetData(fTestNet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, vchSecret.begin(), vchSecret.size()); + if (vchSecret.IsCompressed()) vchData.push_back(1); } - CSecret GetSecret(bool &fCompressedOut) + CKey GetKey() { - CSecret vchSecret; - vchSecret.resize(32); - memcpy(&vchSecret[0], &vchData[0], 32); - fCompressedOut = vchData.size() == 33; - return vchSecret; + CKey ret; + ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1); + return ret; } bool IsValid() const @@ -455,9 +447,9 @@ public: return SetString(strSecret.c_str()); } - CBitcoinSecret(const CSecret& vchSecret, bool fCompressed) + CBitcoinSecret(const CKey& vchSecret) { - SetSecret(vchSecret, fCompressed); + SetKey(vchSecret); } CBitcoinSecret() @@ -465,4 +457,4 @@ public: } }; -#endif +#endif // BITCOIN_BASE58_H diff --git a/src/bignum.h b/src/bignum.h index cb36a1c..0881807 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_BIGNUM_H @@ -133,7 +131,9 @@ public: if (sn < (int64)0) { - // Since the minimum signed integer cannot be represented as positive so long as its type is signed, and it's not well-defined what happens if you make it unsigned before negating it, we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate + // Since the minimum signed integer cannot be represented as positive so long as its type is signed, + // and it's not well-defined what happens if you make it unsigned before negating it, + // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate n = -(sn + 1); ++n; fNegative = true; @@ -222,7 +222,7 @@ public: BN_mpi2bn(pch, p - pch, this); } - uint256 getuint256() + uint256 getuint256() const { unsigned int nSize = BN_bn2mpi(this, NULL); if (nSize < 4) @@ -264,28 +264,68 @@ public: return vch; } + // The "compact" format is a representation of a whole + // number N using an unsigned 32bit number similar to a + // floating point format. + // The most significant 8 bits are the unsigned exponent of base 256. + // This exponent can be thought of as "number of bytes of N". + // The lower 23 bits are the mantissa. + // Bit number 24 (0x800000) represents the sign of N. + // N = (-1^sign) * mantissa * 256^(exponent-3) + // + // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + // MPI uses the most significant bit of the first byte as sign. + // Thus 0x1234560000 is compact (0x05123456) + // and 0xc0de000000 is compact (0x0600c0de) + // (0x05c0de00) would be -0x40de000000 + // + // Bitcoin only uses this "compact" format for encoding difficulty + // targets, which are unsigned 256bit quantities. Thus, all the + // complexities of the sign bit and using base 256 are probably an + // implementation accident. + // + // This implementation directly uses shifts instead of going + // through an intermediate MPI representation. CBigNum& SetCompact(unsigned int nCompact) { unsigned int nSize = nCompact >> 24; - std::vector vch(4 + nSize); - vch[3] = nSize; - if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; - if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; - if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; - BN_mpi2bn(&vch[0], vch.size(), this); + bool fNegative =(nCompact & 0x00800000) != 0; + unsigned int nWord = nCompact & 0x007fffff; + if (nSize <= 3) + { + nWord >>= 8*(3-nSize); + BN_set_word(this, nWord); + } + else + { + BN_set_word(this, nWord); + BN_lshift(this, this, 8*(nSize-3)); + } + BN_set_negative(this, fNegative); return *this; } unsigned int GetCompact() const { - unsigned int nSize = BN_bn2mpi(this, NULL); - std::vector vch(nSize); - nSize -= 4; - BN_bn2mpi(this, &vch[0]); - unsigned int nCompact = nSize << 24; - if (nSize >= 1) nCompact |= (vch[4] << 16); - if (nSize >= 2) nCompact |= (vch[5] << 8); - if (nSize >= 3) nCompact |= (vch[6] << 0); + unsigned int nSize = BN_num_bytes(this); + unsigned int nCompact = 0; + if (nSize <= 3) + nCompact = BN_get_word(this) << 8*(3-nSize); + else + { + CBigNum bn; + BN_rshift(&bn, this, 8*(nSize-3)); + nCompact = BN_get_word(&bn); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) + { + nCompact >>= 8; + nSize++; + } + nCompact |= nSize << 24; + nCompact |= (BN_is_negative(this) ? 0x00800000 : 0); return nCompact; } @@ -307,7 +347,7 @@ public: psz++; // hex string to bignum - static signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,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,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,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,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; *this = 0; while (isxdigit(*psz)) { @@ -418,7 +458,7 @@ public: CBigNum& operator>>=(unsigned int shift) { // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number - // if built on ubuntu 9.04 or 9.10, probably depends on version of openssl + // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL CBigNum a = 1; a <<= shift; if (BN_cmp(&a, this) > 0) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 93eeef6..0bc8500 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1,20 +1,16 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 The CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "main.h" -#include "wallet.h" -#include "db.h" -#include "walletdb.h" -#include "net.h" #include "init.h" +#include "util.h" +#include "sync.h" #include "ui_interface.h" #include "base58.h" #include "bitcoinrpc.h" +#include "db.h" -#undef printf #include #include #include @@ -29,34 +25,22 @@ #include #include -#define printf OutputDebugStringF - using namespace std; using namespace boost; using namespace boost::asio; using namespace json_spirit; -void ThreadRPCServer2(void* parg); - static std::string strRPCUserColonPass; -static int64 nWalletUnlockTime; -static CCriticalSection cs_nWalletUnlockTime; +// These are created by StartRPCThreads, destroyed in StopRPCThreads +static asio::io_service* rpc_io_service = NULL; +static ssl::context* rpc_ssl_context = NULL; +static boost::thread_group* rpc_worker_group = NULL; -extern Value getconnectioncount(const Array& params, bool fHelp); // in rpcnet.cpp -extern Value getpeerinfo(const Array& params, bool fHelp); -extern Value dumpprivkey(const Array& params, bool fHelp); // in rpcdump.cpp -extern Value importprivkey(const Array& params, bool fHelp); -extern Value getrawtransaction(const Array& params, bool fHelp); // in rcprawtransaction.cpp -extern Value listunspent(const Array& params, bool fHelp); -extern Value createrawtransaction(const Array& params, bool fHelp); -extern Value decoderawtransaction(const Array& params, bool fHelp); -extern Value signrawtransaction(const Array& params, bool fHelp); -extern Value sendrawtransaction(const Array& params, bool fHelp); - -const Object emptyobj; - -void ThreadRPCServer3(void* parg); +static inline unsigned short GetDefaultRPCPort() +{ + return GetBoolArg("-testnet", false) ? 17970 : 47970; +} Object JSONRPCError(int code, const string& message) { @@ -65,8 +49,10 @@ Object JSONRPCError(int code, const string& message) error.push_back(Pair("message", message)); return error; } + void RPCTypeCheck(const Array& params, - const list& typesExpected) + const list& typesExpected, + bool fAllowNull) { unsigned int i = 0; BOOST_FOREACH(Value_type t, typesExpected) @@ -74,73 +60,44 @@ void RPCTypeCheck(const Array& params, if (params.size() <= i) break; - const Value& v = params[i]; - if (v.type() != t) + const Value& v = params[i]; + if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) { string err = strprintf("Expected type %s, got %s", Value_type_name[t], Value_type_name[v.type()]); - throw JSONRPCError(-3, err); + throw JSONRPCError(RPC_TYPE_ERROR, err); } i++; } } + void RPCTypeCheck(const Object& o, - const map& typesExpected) + const map& typesExpected, + bool fAllowNull) { BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) { const Value& v = find_value(o, t.first); - if (v.type() == null_type) - throw JSONRPCError(-3, strprintf("Missing %s", t.first.c_str())); - if (v.type() != t.second) + if (!fAllowNull && v.type() == null_type) + throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first.c_str())); + + if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type)))) { string err = strprintf("Expected type %s for %s, got %s", Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]); - throw JSONRPCError(-3, err); + throw JSONRPCError(RPC_TYPE_ERROR, err); } } } -double GetDifficulty(const CBlockIndex* blockindex = NULL) -{ - // Floating point number that is a multiple of the minimum difficulty, - // minimum difficulty = 1.0. - if (blockindex == NULL) - { - if (pindexBest == NULL) - return 1.0; - else - blockindex = pindexBest; - } - - int nShift = (blockindex->nBits >> 24) & 0xff; - - double dDiff = - (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff); - - while (nShift < 29) - { - dDiff *= 256.0; - nShift++; - } - while (nShift > 29) - { - dDiff /= 256.0; - nShift--; - } - - return dDiff; -} - - int64 AmountFromValue(const Value& value) { double dAmount = value.get_real(); if (dAmount <= 0.0 || dAmount > 84000000.0) - throw JSONRPCError(-3, "Invalid amount"); + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); int64 nAmount = roundint64(dAmount * COIN); if (!MoneyRange(nAmount)) - throw JSONRPCError(-3, "Invalid amount"); + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); return nAmount; } @@ -149,8 +106,7 @@ Value ValueFromAmount(int64 amount) return (double)amount / (double)COIN; } -std::string -HexBits(unsigned int nBits) +std::string HexBits(unsigned int nBits) { union { int32_t nBits; @@ -160,72 +116,11 @@ HexBits(unsigned int nBits) return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); } -std::string -HelpRequiringPassphrase() -{ - return pwalletMain->IsCrypted() - ? "\nrequires wallet passphrase to be set with walletpassphrase first" - : ""; -} -void -EnsureWalletIsUnlocked() -{ - if (pwalletMain->IsLocked()) - throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); -} - -void WalletTxToJSON(const CWalletTx& wtx, Object& entry) -{ - int confirms = wtx.GetDepthInMainChain(); - entry.push_back(Pair("confirmations", confirms)); - if (confirms) - { - entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); - entry.push_back(Pair("blockindex", wtx.nIndex)); - } - entry.push_back(Pair("txid", wtx.GetHash().GetHex())); - entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); - BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) - entry.push_back(Pair(item.first, item.second)); -} - -string AccountFromValue(const Value& value) -{ - string strAccount = value.get_str(); - if (strAccount == "*") - throw JSONRPCError(-11, "Invalid account name"); - return strAccount; -} - -Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) -{ - Object result; - result.push_back(Pair("hash", block.GetHash().GetHex())); - CMerkleTx txGen(block.vtx[0]); - txGen.SetMerkleBranch(&block); - result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); - result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); - result.push_back(Pair("height", blockindex->nHeight)); - result.push_back(Pair("version", block.nVersion)); - result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - Array txs; - BOOST_FOREACH(const CTransaction&tx, block.vtx) - txs.push_back(tx.GetHash().GetHex()); - result.push_back(Pair("tx", txs)); - result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); - result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); - result.push_back(Pair("bits", HexBits(block.nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); - - if (blockindex->pprev) - result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - if (blockindex->pnext) - result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); - return result; -} +/// /// Note: This interface may still be subject to change. +/// string CRPCTable::help(string strCommand) const { @@ -240,6 +135,9 @@ string CRPCTable::help(string strCommand) const continue; if (strCommand != "" && strMethod != strCommand) continue; + if (pcmd->reqWallet && !pwalletMain) + continue; + try { Array params; @@ -280,2046 +178,17 @@ Value help(const Array& params, bool fHelp) Value stop(const Array& params, bool fHelp) { - if (fHelp || params.size() != 0) + // Accept the deprecated and ignored 'detach' boolean argument + if (fHelp || params.size() > 1) throw runtime_error( "stop\n" "Stop CasinoCoin server."); // Shutdown will take long enough that the response should get back StartShutdown(); - return "CasinoCoin server has now stopped running!"; + return "CasinoCoin server stopping"; } -Value getblockcount(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getblockcount\n" - "Returns the number of blocks in the longest block chain."); - - return nBestHeight; -} - - -Value getdifficulty(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getdifficulty\n" - "Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); - - return GetDifficulty(); -} - - -// CasinoCoin: Return average network hashes per second based on last number of blocks. -Value GetNetworkHashPS(int lookup) { - if (pindexBest == NULL) - return 0; - - // If lookup is -1, then use blocks since last difficulty change. - if (lookup <= 0) - lookup = pindexBest->nHeight % 2016 + 1; - - // If lookup is larger than chain, then set it to chain length. - if (lookup > pindexBest->nHeight) - lookup = pindexBest->nHeight; - - CBlockIndex* pindexPrev = pindexBest; - for (int i = 0; i < lookup; i++) - pindexPrev = pindexPrev->pprev; - - double timeDiff = pindexBest->GetBlockTime() - pindexPrev->GetBlockTime(); - double timePerBlock = timeDiff / lookup; - - return (boost::int64_t)(((double)GetDifficulty() * pow(2.0, 32)) / timePerBlock); -} - -Value getnetworkhashps(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getnetworkhashps [blocks]\n" - "Returns the estimated network hashes per second based on the last 8 blocks.\n" - "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change."); - - return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120); -} - - -Value getgenerate(const Array& params, bool fHelp) -{ - throw runtime_error("The getgenerate command has been disabled."); - return false; - - if (fHelp || params.size() != 0) - throw runtime_error( - "getgenerate\n" - "Returns true or false."); - - return GetBoolArg("-gen"); -} - - -Value setgenerate(const Array& params, bool fHelp) -{ - throw runtime_error("The setgenerate command has been disabled."); - return Value::null; - - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "setgenerate [genproclimit]\n" - " is true or false to turn generation on or off.\n" - "Generation is limited to [genproclimit] processors, -1 is unlimited."); - - bool fGenerate = true; - if (params.size() > 0) - fGenerate = params[0].get_bool(); - - if (params.size() > 1) - { - int nGenProcLimit = params[1].get_int(); - mapArgs["-genproclimit"] = itostr(nGenProcLimit); - if (nGenProcLimit == 0) - fGenerate = false; - } - mapArgs["-gen"] = (fGenerate ? "1" : "0"); - - GenerateBitcoins(fGenerate, pwalletMain); - return Value::null; -} - - -Value gethashespersec(const Array& params, bool fHelp) -{ - // Disabled mining, so therefore we will return 0. - return (boost::int64_t)0; - - if (fHelp || params.size() != 0) - throw runtime_error( - "gethashespersec\n" - "Returns a recent hashes per second performance measurement while generating."); - - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (boost::int64_t)0; - return (boost::int64_t)dHashesPerSec; -} - - -Value getinfo(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getinfo\n" - "Returns an object containing various state info."); - - CService addrProxy; - GetProxy(NET_IPV4, addrProxy); - - Object obj; - obj.push_back(Pair("version", (int)CLIENT_VERSION)); - obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); - obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); - obj.push_back(Pair("blocks", (int)nBestHeight)); - obj.push_back(Pair("connections", (int)vNodes.size())); - obj.push_back(Pair("proxy", (addrProxy.IsValid() ? addrProxy.ToStringIPPort() : string()))); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("testnet", fTestNet)); - obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); - obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); - obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue))); - if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - return obj; -} - - -Value getmininginfo(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getmininginfo\n" - "Returns an object containing mining-related information."); - - Object obj; - obj.push_back(Pair("blocks", (int)nBestHeight)); - obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); - 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("generate", GetBoolArg("-gen"))); - obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); - obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); - obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", fTestNet)); - return obj; -} - - -Value getnewaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getnewaddress [account]\n" - "Returns a new CasinoCoin address for receiving payments. " - "If [account] is specified (recommended), it is added to the address book " - "so payments received with the address will be credited to [account]."); - - // 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]); - - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); - - // Generate a new key that is added to wallet - CPubKey newKey; - if (!pwalletMain->GetKeyFromPool(newKey, false)) - throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first"); - CKeyID keyID = newKey.GetID(); - - pwalletMain->SetAddressBookName(keyID, strAccount); - - return CBitcoinAddress(keyID).ToString(); -} - - -CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) -{ - CWalletDB walletdb(pwalletMain->strWalletFile); - - CAccount account; - walletdb.ReadAccount(strAccount, account); - - bool bKeyUsed = false; - - // Check if the current key has been used - if (account.vchPubKey.IsValid()) - { - CScript scriptPubKey; - scriptPubKey.SetDestination(account.vchPubKey.GetID()); - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); - ++it) - { - const CWalletTx& wtx = (*it).second; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - bKeyUsed = true; - } - } - - // Generate a new key - if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) - { - if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false)) - throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first"); - - pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount); - walletdb.WriteAccount(strAccount, account); - } - - return CBitcoinAddress(account.vchPubKey.GetID()); -} - -Value getaccountaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getaccountaddress \n" - "Returns the current CasinoCoin address for receiving payments to this account."); - - // Parse the account first so we don't generate a key if there's an error - string strAccount = AccountFromValue(params[0]); - - Value ret; - - ret = GetAccountAddress(strAccount).ToString(); - - return ret; -} - - - -Value setaccount(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "setaccount \n" - "Sets the account associated with the given address."); - - CBitcoinAddress address(params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(-5, "Invalid CasinoCoin address"); - - - string strAccount; - if (params.size() > 1) - strAccount = AccountFromValue(params[1]); - - // 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()]; - if (address == GetAccountAddress(strOldAccount)) - GetAccountAddress(strOldAccount, true); - } - - pwalletMain->SetAddressBookName(address.Get(), strAccount); - - return Value::null; -} - - -Value getaccount(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getaccount \n" - "Returns the account associated with the given address."); - - CBitcoinAddress address(params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(-5, "Invalid CasinoCoin address"); - - string strAccount; - map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); - if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) - strAccount = (*mi).second; - return strAccount; -} - - -Value getaddressesbyaccount(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getaddressesbyaccount \n" - "Returns the list of addresses for the given account."); - - string strAccount = AccountFromValue(params[0]); - - // Find all addresses that have the given account - Array ret; - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) - { - const CBitcoinAddress& address = item.first; - const string& strName = item.second; - if (strName == strAccount) - ret.push_back(address.ToString()); - } - return ret; -} - -Value settxfee(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "settxfee \n" - " is a real and is rounded to the nearest 0.00000001"); - - // Amount - int64 nAmount = 0; - if (params[0].get_real() != 0.0) - nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts - - nTransactionFee = nAmount; - return true; -} - -Value setmininput(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "setmininput \n" - " is a real and is rounded to the nearest 0.00000001"); - - // Amount - int64 nAmount = 0; - if (params[0].get_real() != 0.0) - nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts - - nMinimumInputValue = nAmount; - return true; -} - -Value sendtoaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( - "sendtoaddress [comment] [comment-to]\n" - " is a real and is rounded to the nearest 0.00000001" - + HelpRequiringPassphrase()); - - CBitcoinAddress address(params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(-5, "Invalid CasinoCoin address"); - - // Amount - int64 nAmount = AmountFromValue(params[1]); - - // Wallet comments - CWalletTx wtx; - if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) - wtx.mapValue["comment"] = params[2].get_str(); - if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) - wtx.mapValue["to"] = params[3].get_str(); - - if (pwalletMain->IsLocked()) - throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); - - string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); - if (strError != "") - throw JSONRPCError(-4, strError); - - return wtx.GetHash().GetHex(); -} - -Value signmessage(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "signmessage \n" - "Sign a message with the private key of an address"); - - EnsureWalletIsUnlocked(); - - string strAddress = params[0].get_str(); - string strMessage = params[1].get_str(); - - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) - throw JSONRPCError(-3, "Invalid address"); - - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - throw JSONRPCError(-3, "Address does not refer to key"); - - CKey key; - if (!pwalletMain->GetKey(keyID, key)) - throw JSONRPCError(-4, "Private key not available"); - - CDataStream ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - vector vchSig; - if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) - throw JSONRPCError(-5, "Sign failed"); - - return EncodeBase64(&vchSig[0], vchSig.size()); -} - -Value verifymessage(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 3) - throw runtime_error( - "verifymessage \n" - "Verify a signed message"); - - string strAddress = params[0].get_str(); - string strSign = params[1].get_str(); - string strMessage = params[2].get_str(); - - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) - throw JSONRPCError(-3, "Invalid address"); - - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - throw JSONRPCError(-3, "Address does not refer to key"); - - bool fInvalid = false; - vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); - - if (fInvalid) - throw JSONRPCError(-5, "Malformed base64 encoding"); - - CDataStream ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - CKey key; - if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) - return false; - - return (key.GetPubKey().GetID() == keyID); -} - - -Value getreceivedbyaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getreceivedbyaddress [minconf=1]\n" - "Returns the total amount received by in transactions with at least [minconf] confirmations."); - - // CasinoCoin address - CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); - CScript scriptPubKey; - if (!address.IsValid()) - throw JSONRPCError(-5, "Invalid CasinoCoin address"); - scriptPubKey.SetDestination(address.Get()); - if (!IsMine(*pwalletMain,scriptPubKey)) - return (double)0.0; - - // Minimum confirmations - int nMinDepth = 1; - if (params.size() > 1) - nMinDepth = params[1].get_int(); - - // Tally - int64 nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !wtx.IsFinal()) - continue; - - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - if (wtx.GetDepthInMainChain() >= nMinDepth) - nAmount += txout.nValue; - } - - return ValueFromAmount(nAmount); -} - - -void GetAccountAddresses(string strAccount, set& setAddress) -{ - BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook) - { - const CTxDestination& address = item.first; - const string& strName = item.second; - if (strName == strAccount) - setAddress.insert(address); - } -} - -Value getreceivedbyaccount(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getreceivedbyaccount [minconf=1]\n" - "Returns the total amount received by addresses with in transactions with at least [minconf] confirmations."); - - // Minimum confirmations - int nMinDepth = 1; - if (params.size() > 1) - nMinDepth = params[1].get_int(); - - // Get the set of pub keys assigned to account - string strAccount = AccountFromValue(params[0]); - set setAddress; - GetAccountAddresses(strAccount, setAddress); - - // Tally - int64 nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !wtx.IsFinal()) - continue; - - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - { - CTxDestination address; - if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) - if (wtx.GetDepthInMainChain() >= nMinDepth) - nAmount += txout.nValue; - } - } - - return (double)nAmount / (double)COIN; -} - - -int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) -{ - int64 nBalance = 0; - - // Tally wallet transactions - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - if (!wtx.IsFinal()) - continue; - - int64 nGenerated, nReceived, nSent, nFee; - wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee); - - if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) - nBalance += nReceived; - nBalance += nGenerated - nSent - nFee; - } - - // Tally internal accounting entries - nBalance += walletdb.GetAccountCreditDebit(strAccount); - - return nBalance; -} - -int64 GetAccountBalance(const string& strAccount, int nMinDepth) -{ - CWalletDB walletdb(pwalletMain->strWalletFile); - return GetAccountBalance(walletdb, strAccount, nMinDepth); -} - - -Value getbalance(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "getbalance [account] [minconf=1]\n" - "If [account] is not specified, returns the server's total available balance.\n" - "If [account] is specified, returns the balance in the account."); - - if (params.size() == 0) - return ValueFromAmount(pwalletMain->GetBalance()); - - int nMinDepth = 1; - if (params.size() > 1) - nMinDepth = params[1].get_int(); - - if (params[0].get_str() == "*") { - // Calculate total balance a different way from GetBalance() - // (GetBalance() sums up all unspent TxOuts) - // getbalance and getbalance '*' should always return the same number. - int64 nBalance = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - if (!wtx.IsFinal()) - continue; - - int64 allGeneratedImmature, allGeneratedMature, allFee; - allGeneratedImmature = allGeneratedMature = allFee = 0; - string strSentAccount; - list > listReceived; - list > listSent; - wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); - if (wtx.GetDepthInMainChain() >= nMinDepth) - { - BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived) - nBalance += r.second; - } - BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent) - nBalance -= r.second; - nBalance -= allFee; - nBalance += allGeneratedMature; - } - return ValueFromAmount(nBalance); - } - - string strAccount = AccountFromValue(params[0]); - - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); - - return ValueFromAmount(nBalance); -} - - -Value movecmd(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 3 || params.size() > 5) - throw runtime_error( - "move [minconf=1] [comment]\n" - "Move from one account in your wallet to another."); - - string strFrom = AccountFromValue(params[0]); - string strTo = AccountFromValue(params[1]); - int64 nAmount = AmountFromValue(params[2]); - if (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(); - - CWalletDB walletdb(pwalletMain->strWalletFile); - if (!walletdb.TxnBegin()) - throw JSONRPCError(-20, "database error"); - - int64 nNow = GetAdjustedTime(); - - // Debit - CAccountingEntry debit; - debit.strAccount = strFrom; - debit.nCreditDebit = -nAmount; - debit.nTime = nNow; - debit.strOtherAccount = strTo; - debit.strComment = strComment; - walletdb.WriteAccountingEntry(debit); - - // Credit - CAccountingEntry credit; - credit.strAccount = strTo; - credit.nCreditDebit = nAmount; - credit.nTime = nNow; - credit.strOtherAccount = strFrom; - credit.strComment = strComment; - walletdb.WriteAccountingEntry(credit); - - if (!walletdb.TxnCommit()) - throw JSONRPCError(-20, "database error"); - - return true; -} - - -Value sendfrom(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 3 || params.size() > 6) - throw runtime_error( - "sendfrom [minconf=1] [comment] [comment-to]\n" - " is a real and is rounded to the nearest 0.00000001" - + HelpRequiringPassphrase()); - - string strAccount = AccountFromValue(params[0]); - CBitcoinAddress address(params[1].get_str()); - if (!address.IsValid()) - throw JSONRPCError(-5, "Invalid CasinoCoin address"); - int64 nAmount = AmountFromValue(params[2]); - int nMinDepth = 1; - if (params.size() > 3) - nMinDepth = params[3].get_int(); - - CWalletTx wtx; - wtx.strFromAccount = strAccount; - if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty()) - wtx.mapValue["comment"] = params[4].get_str(); - if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty()) - wtx.mapValue["to"] = params[5].get_str(); - - EnsureWalletIsUnlocked(); - - // Check funds - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); - if (nAmount > nBalance) - throw JSONRPCError(-6, "Account has insufficient funds"); - - // Send - string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); - if (strError != "") - throw JSONRPCError(-4, strError); - - return wtx.GetHash().GetHex(); -} - - -Value sendmany(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( - "sendmany {address:amount,...} [minconf=1] [comment]\n" - "amounts are double-precision floating point numbers" - + HelpRequiringPassphrase()); - - string strAccount = AccountFromValue(params[0]); - Object sendTo = params[1].get_obj(); - int nMinDepth = 1; - if (params.size() > 2) - nMinDepth = params[2].get_int(); - - CWalletTx wtx; - wtx.strFromAccount = strAccount; - if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) - wtx.mapValue["comment"] = params[3].get_str(); - - set setAddress; - vector > vecSend; - - int64 totalAmount = 0; - BOOST_FOREACH(const Pair& s, sendTo) - { - CBitcoinAddress address(s.name_); - if (!address.IsValid()) - throw JSONRPCError(-5, string("Invalid CasinoCoin address:")+s.name_); - - if (setAddress.count(address)) - throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_); - setAddress.insert(address); - - CScript scriptPubKey; - scriptPubKey.SetDestination(address.Get()); - int64 nAmount = AmountFromValue(s.value_); - totalAmount += nAmount; - - vecSend.push_back(make_pair(scriptPubKey, nAmount)); - } - - EnsureWalletIsUnlocked(); - - // Check funds - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); - if (totalAmount > nBalance) - throw JSONRPCError(-6, "Account has insufficient funds"); - - // Send - CReserveKey keyChange(pwalletMain); - int64 nFeeRequired = 0; - bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); - if (!fCreated) - { - if (totalAmount + nFeeRequired > pwalletMain->GetBalance()) - throw JSONRPCError(-6, "Insufficient funds"); - throw JSONRPCError(-4, "Transaction creation failed"); - } - if (!pwalletMain->CommitTransaction(wtx, keyChange)) - throw JSONRPCError(-4, "Transaction commit failed"); - - return wtx.GetHash().GetHex(); -} - -Value addmultisigaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 3) - { - string msg = "addmultisigaddress <'[\"key\",\"key\"]'> [account]\n" - "Add a nrequired-to-sign multisignature address to the wallet\"\n" - "each key is a CasinoCoin address or hex-encoded public key\n" - "If [account] is specified, assign address to [account]."; - throw runtime_error(msg); - } - - int nRequired = params[0].get_int(); - const Array& keys = params[1].get_array(); - string strAccount; - if (params.size() > 2) - strAccount = AccountFromValue(params[2]); - - // Gather public keys - if (nRequired < 1) - throw runtime_error("a multisignature address must require at least one key to redeem"); - if ((int)keys.size() < nRequired) - throw runtime_error( - strprintf("not enough keys supplied " - "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired)); - std::vector pubkeys; - pubkeys.resize(keys.size()); - for (unsigned int i = 0; i < keys.size(); i++) - { - const std::string& ks = keys[i].get_str(); - - // Case 1: CasinoCoin address and we have full public key: - CBitcoinAddress address(ks); - if (address.IsValid()) - { - CKeyID keyID; - if (!address.GetKeyID(keyID)) - throw runtime_error( - strprintf("%s does not refer to a key",ks.c_str())); - CPubKey vchPubKey; - if (!pwalletMain->GetPubKey(keyID, vchPubKey)) - throw runtime_error( - strprintf("no full public key for address %s",ks.c_str())); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) - throw runtime_error(" Invalid public key: "+ks); - } - - // Case 2: hex public key - else if (IsHex(ks)) - { - CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) - throw runtime_error(" Invalid public key: "+ks); - } - else - { - throw runtime_error(" Invalid public key: "+ks); - } - } - - // Construct using pay-to-script-hash: - CScript inner; - inner.SetMultisig(nRequired, pubkeys); - CScriptID innerID = inner.GetID(); - pwalletMain->AddCScript(inner); - - pwalletMain->SetAddressBookName(innerID, strAccount); - return CBitcoinAddress(innerID).ToString(); -} - - -struct tallyitem -{ - int64 nAmount; - int nConf; - tallyitem() - { - nAmount = 0; - nConf = std::numeric_limits::max(); - } -}; - -Value ListReceived(const Array& params, bool fByAccounts) -{ - // Minimum confirmations - int nMinDepth = 1; - if (params.size() > 0) - nMinDepth = params[0].get_int(); - - // Whether to include empty accounts - bool fIncludeEmpty = false; - if (params.size() > 1) - fIncludeEmpty = params[1].get_bool(); - - // Tally - map mapTally; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - - if (wtx.IsCoinBase() || !wtx.IsFinal()) - continue; - - int nDepth = wtx.GetDepthInMainChain(); - if (nDepth < nMinDepth) - continue; - - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - { - CTxDestination address; - if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address)) - continue; - - tallyitem& item = mapTally[address]; - item.nAmount += txout.nValue; - item.nConf = min(item.nConf, nDepth); - } - } - - // Reply - Array ret; - map mapAccountTally; - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) - { - const CBitcoinAddress& address = item.first; - const string& strAccount = item.second; - map::iterator it = mapTally.find(address); - if (it == mapTally.end() && !fIncludeEmpty) - continue; - - int64 nAmount = 0; - int nConf = std::numeric_limits::max(); - if (it != mapTally.end()) - { - nAmount = (*it).second.nAmount; - nConf = (*it).second.nConf; - } - - if (fByAccounts) - { - tallyitem& item = mapAccountTally[strAccount]; - item.nAmount += nAmount; - item.nConf = min(item.nConf, nConf); - } - else - { - Object obj; - obj.push_back(Pair("address", address.ToString())); - obj.push_back(Pair("account", strAccount)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); - obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); - ret.push_back(obj); - } - } - - if (fByAccounts) - { - for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) - { - int64 nAmount = (*it).second.nAmount; - int nConf = (*it).second.nConf; - Object obj; - obj.push_back(Pair("account", (*it).first)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); - obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); - ret.push_back(obj); - } - } - - return ret; -} - -Value listreceivedbyaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "listreceivedbyaddress [minconf=1] [includeempty=false]\n" - "[minconf] is the minimum number of confirmations before payments are included.\n" - "[includeempty] whether to include addresses that haven't received any payments.\n" - "Returns an array of objects containing:\n" - " \"address\" : receiving address\n" - " \"account\" : the account of the receiving address\n" - " \"amount\" : total amount received by the address\n" - " \"confirmations\" : number of confirmations of the most recent transaction included"); - - return ListReceived(params, false); -} - -Value listreceivedbyaccount(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "listreceivedbyaccount [minconf=1] [includeempty=false]\n" - "[minconf] is the minimum number of confirmations before payments are included.\n" - "[includeempty] whether to include accounts that haven't received any payments.\n" - "Returns an array of objects containing:\n" - " \"account\" : the account of the receiving addresses\n" - " \"amount\" : total amount received by addresses with this account\n" - " \"confirmations\" : number of confirmations of the most recent transaction included"); - - return ListReceived(params, true); -} - -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret) -{ - int64 nGeneratedImmature, nGeneratedMature, nFee; - string strSentAccount; - list > listReceived; - list > listSent; - - wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); - - bool fAllAccounts = (strAccount == string("*")); - - // Generated blocks assigned to account "" - if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == "")) - { - Object entry; - entry.push_back(Pair("account", string(""))); - if (nGeneratedImmature) - { - entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan")); - entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature))); - } - else - { - entry.push_back(Pair("category", "generate")); - entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature))); - } - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); - } - - // Sent - if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) - { - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) - { - Object entry; - entry.push_back(Pair("account", strSentAccount)); - entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString())); - entry.push_back(Pair("category", "send")); - entry.push_back(Pair("amount", ValueFromAmount(-s.second))); - entry.push_back(Pair("fee", ValueFromAmount(-nFee))); - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); - } - } - - // Received - if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) - { - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) - { - string account; - if (pwalletMain->mapAddressBook.count(r.first)) - account = pwalletMain->mapAddressBook[r.first]; - if (fAllAccounts || (account == strAccount)) - { - Object entry; - entry.push_back(Pair("account", account)); - entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString())); - entry.push_back(Pair("category", "receive")); - entry.push_back(Pair("amount", ValueFromAmount(r.second))); - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); - } - } - } -} - -void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret) -{ - bool fAllAccounts = (strAccount == string("*")); - - if (fAllAccounts || acentry.strAccount == strAccount) - { - Object entry; - entry.push_back(Pair("account", acentry.strAccount)); - entry.push_back(Pair("category", "move")); - entry.push_back(Pair("time", (boost::int64_t)acentry.nTime)); - entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); - entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); - entry.push_back(Pair("comment", acentry.strComment)); - ret.push_back(entry); - } -} - -Value listtransactions(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 3) - throw runtime_error( - "listtransactions [account] [count=10] [from=0]\n" - "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account]."); - - string strAccount = "*"; - if (params.size() > 0) - strAccount = params[0].get_str(); - int nCount = 10; - if (params.size() > 1) - nCount = params[1].get_int(); - int nFrom = 0; - if (params.size() > 2) - nFrom = params[2].get_int(); - - if (nCount < 0) - throw JSONRPCError(-8, "Negative count"); - if (nFrom < 0) - throw JSONRPCError(-8, "Negative from"); - - Array ret; - CWalletDB walletdb(pwalletMain->strWalletFile); - - // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. - typedef pair TxPair; - typedef multimap TxItems; - TxItems txByTime; - - // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry - // would make this much faster for applications that do this a lot. - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - CWalletTx* wtx = &((*it).second); - txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0))); - } - list acentries; - walletdb.ListAccountCreditDebit(strAccount, acentries); - BOOST_FOREACH(CAccountingEntry& entry, acentries) - { - txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); - } - - // iterate backwards until we have nCount items to return: - for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it) - { - CWalletTx *const pwtx = (*it).second.first; - if (pwtx != 0) - ListTransactions(*pwtx, strAccount, 0, true, ret); - CAccountingEntry *const pacentry = (*it).second.second; - if (pacentry != 0) - AcentryToJSON(*pacentry, strAccount, ret); - - if ((int)ret.size() >= (nCount+nFrom)) break; - } - // ret is newest to oldest - - if (nFrom > (int)ret.size()) - nFrom = ret.size(); - if ((nFrom + nCount) > (int)ret.size()) - nCount = ret.size() - nFrom; - Array::iterator first = ret.begin(); - std::advance(first, nFrom); - Array::iterator last = ret.begin(); - std::advance(last, nFrom+nCount); - - if (last != ret.end()) ret.erase(last, ret.end()); - if (first != ret.begin()) ret.erase(ret.begin(), first); - - std::reverse(ret.begin(), ret.end()); // Return oldest to newest - - return ret; -} - -Value listaccounts(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "listaccounts [minconf=1]\n" - "Returns Object that has account names as keys, account balances as values."); - - int nMinDepth = 1; - if (params.size() > 0) - nMinDepth = params[0].get_int(); - - map mapAccountBalances; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { - if (IsMine(*pwalletMain, entry.first)) // This address belongs to me - mapAccountBalances[entry.second] = 0; - } - - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; - int64 nGeneratedImmature, nGeneratedMature, nFee; - string strSentAccount; - list > listReceived; - list > listSent; - wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); - mapAccountBalances[strSentAccount] -= nFee; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) - mapAccountBalances[strSentAccount] -= s.second; - if (wtx.GetDepthInMainChain() >= nMinDepth) - { - mapAccountBalances[""] += nGeneratedMature; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) - if (pwalletMain->mapAddressBook.count(r.first)) - mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; - else - mapAccountBalances[""] += r.second; - } - } - - list acentries; - CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); - BOOST_FOREACH(const CAccountingEntry& entry, acentries) - mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - - Object ret; - BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) { - ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); - } - return ret; -} - -Value listsinceblock(const Array& params, bool fHelp) -{ - if (fHelp) - throw runtime_error( - "listsinceblock [blockhash] [target-confirmations]\n" - "Get all transactions in blocks since block [blockhash], or all transactions if omitted"); - - CBlockIndex *pindex = NULL; - int target_confirms = 1; - - if (params.size() > 0) - { - uint256 blockId = 0; - - blockId.SetHex(params[0].get_str()); - pindex = CBlockLocator(blockId).GetBlockIndex(); - } - - if (params.size() > 1) - { - target_confirms = params[1].get_int(); - - if (target_confirms < 1) - throw JSONRPCError(-8, "Invalid parameter"); - } - - int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; - - Array transactions; - - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) - { - CWalletTx tx = (*it).second; - - if (depth == -1 || tx.GetDepthInMainChain() < depth) - ListTransactions(tx, "*", 0, true, transactions); - } - - uint256 lastblock; - - if (target_confirms == 1) - { - lastblock = hashBestChain; - } - else - { - int target_height = pindexBest->nHeight + 1 - target_confirms; - - CBlockIndex *block; - for (block = pindexBest; - block && block->nHeight > target_height; - block = block->pprev) { } - - lastblock = block ? block->GetBlockHash() : 0; - } - - Object ret; - ret.push_back(Pair("transactions", transactions)); - ret.push_back(Pair("lastblock", lastblock.GetHex())); - - return ret; -} - -Value gettransaction(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "gettransaction \n" - "Get detailed information about in-wallet transaction "); - - uint256 hash; - hash.SetHex(params[0].get_str()); - - Object entry; - if (!pwalletMain->mapWallet.count(hash)) - throw JSONRPCError(-5, "Invalid or non-wallet transaction id"); - const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); - int64 nNet = nCredit - nDebit; - int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); - - entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); - if (wtx.IsFromMe()) - entry.push_back(Pair("fee", ValueFromAmount(nFee))); - - WalletTxToJSON(wtx, entry); - - Array details; - ListTransactions(wtx, "*", 0, false, details); - entry.push_back(Pair("details", details)); - - return entry; -} - - -Value backupwallet(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "backupwallet \n" - "Safely copies wallet.dat to destination, which can be a directory or a path with filename."); - - string strDest = params[0].get_str(); - BackupWallet(*pwalletMain, strDest); - - return Value::null; -} - - -Value keypoolrefill(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 0) - throw runtime_error( - "keypoolrefill\n" - "Fills the keypool." - + HelpRequiringPassphrase()); - - EnsureWalletIsUnlocked(); - - pwalletMain->TopUpKeyPool(); - - if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100)) - throw JSONRPCError(-4, "Error refreshing keypool."); - - return Value::null; -} - - -void ThreadTopUpKeyPool(void* parg) -{ - // Make this thread recognisable as the key-topping-up thread - RenameThread("bitcoin-key-top"); - - pwalletMain->TopUpKeyPool(); -} - -void ThreadCleanWalletPassphrase(void* parg) -{ - // Make this thread recognisable as the wallet relocking thread - RenameThread("bitcoin-lock-wa"); - - int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000; - - ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - - if (nWalletUnlockTime == 0) - { - nWalletUnlockTime = nMyWakeTime; - - do - { - if (nWalletUnlockTime==0) - break; - int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); - if (nToSleep <= 0) - break; - - LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); - Sleep(nToSleep); - ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - - } while(1); - - if (nWalletUnlockTime) - { - nWalletUnlockTime = 0; - pwalletMain->Lock(); - } - } - else - { - if (nWalletUnlockTime < nMyWakeTime) - nWalletUnlockTime = nMyWakeTime; - } - - LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); - - delete (int64*)parg; -} - -Value walletpassphrase(const Array& params, bool fHelp) -{ - if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) - throw runtime_error( - "walletpassphrase \n" - "Stores the wallet decryption key in memory for seconds."); - if (fHelp) - return true; - if (!pwalletMain->IsCrypted()) - throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called."); - - if (!pwalletMain->IsLocked()) - throw JSONRPCError(-17, "Error: Wallet is already unlocked."); - - // Note that the walletpassphrase is stored in 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(); - - if (strWalletPass.length() > 0) - { - if (!pwalletMain->Unlock(strWalletPass)) - throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); - } - else - throw runtime_error( - "walletpassphrase \n" - "Stores the wallet decryption key in memory for seconds."); - - CreateThread(ThreadTopUpKeyPool, NULL); - int64* pnSleepTime = new int64(params[1].get_int64()); - CreateThread(ThreadCleanWalletPassphrase, pnSleepTime); - - return Value::null; -} - - -Value walletpassphrasechange(const Array& params, bool fHelp) -{ - if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) - throw runtime_error( - "walletpassphrasechange \n" - "Changes the wallet passphrase from to ."); - if (fHelp) - return true; - if (!pwalletMain->IsCrypted()) - throw JSONRPCError(-15, "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. - SecureString strOldWalletPass; - strOldWalletPass.reserve(100); - strOldWalletPass = params[0].get_str().c_str(); - - SecureString strNewWalletPass; - strNewWalletPass.reserve(100); - strNewWalletPass = params[1].get_str().c_str(); - - if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) - throw runtime_error( - "walletpassphrasechange \n" - "Changes the wallet passphrase from to ."); - - if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) - throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); - - return Value::null; -} - - -Value walletlock(const Array& params, bool fHelp) -{ - if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) - throw runtime_error( - "walletlock\n" - "Removes the wallet encryption key from memory, locking the wallet.\n" - "After calling this method, you will need to call walletpassphrase again\n" - "before being able to call any methods which require the wallet to be unlocked."); - if (fHelp) - return true; - if (!pwalletMain->IsCrypted()) - throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called."); - - { - LOCK(cs_nWalletUnlockTime); - pwalletMain->Lock(); - nWalletUnlockTime = 0; - } - - return Value::null; -} - - -Value encryptwallet(const Array& params, bool fHelp) -{ - if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) - throw runtime_error( - "encryptwallet \n" - "Encrypts the wallet with ."); - if (fHelp) - return true; - if (pwalletMain->IsCrypted()) - throw JSONRPCError(-15, "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. - SecureString strWalletPass; - strWalletPass.reserve(100); - strWalletPass = params[0].get_str().c_str(); - - if (strWalletPass.length() < 1) - throw runtime_error( - "encryptwallet \n" - "Encrypts the wallet with ."); - - if (!pwalletMain->EncryptWallet(strWalletPass)) - throw JSONRPCError(-16, "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; CasinoCoin server stopping, restart to run with encrypted wallet"; -} - -class DescribeAddressVisitor : public boost::static_visitor -{ -public: - Object operator()(const CNoDestination &dest) const { return Object(); } - - Object operator()(const CKeyID &keyID) const { - Object obj; - CPubKey vchPubKey; - pwalletMain->GetPubKey(keyID, vchPubKey); - obj.push_back(Pair("isscript", false)); - obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw()))); - obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); - return obj; - } - - Object operator()(const CScriptID &scriptID) const { - Object obj; - obj.push_back(Pair("isscript", true)); - CScript subscript; - pwalletMain->GetCScript(scriptID, subscript); - std::vector addresses; - txnouttype whichType; - int nRequired; - ExtractDestinations(subscript, whichType, addresses, nRequired); - obj.push_back(Pair("script", GetTxnOutputType(whichType))); - Array a; - BOOST_FOREACH(const CTxDestination& addr, addresses) - a.push_back(CBitcoinAddress(addr).ToString()); - obj.push_back(Pair("addresses", a)); - if (whichType == TX_MULTISIG) - obj.push_back(Pair("sigsrequired", nRequired)); - return obj; - } -}; - -Value validateaddress(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "validateaddress \n" - "Return information about ."); - - CBitcoinAddress address(params[0].get_str()); - bool isValid = address.IsValid(); - - Object ret; - ret.push_back(Pair("isvalid", isValid)); - if (isValid) - { - CTxDestination dest = address.Get(); - string currentAddress = address.ToString(); - ret.push_back(Pair("address", currentAddress)); - bool fMine = IsMine(*pwalletMain, dest); - ret.push_back(Pair("ismine", fMine)); - if (fMine) { - Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); - ret.insert(ret.end(), detail.begin(), detail.end()); - } - if (pwalletMain->mapAddressBook.count(dest)) - ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); - } - return ret; -} - -Value getworkex(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "getworkex [data, coinbase]\n" - "If [data, coinbase] is not specified, returns extended work data.\n" - ); - - if (vNodes.empty()) - throw JSONRPCError(-9, "CasinoCoin is not connected!"); - - if (IsInitialBlockDownload()) - throw JSONRPCError(-10, "CasinoCoin is downloading blocks..."); - - typedef map > mapNewBlock_t; - static mapNewBlock_t mapNewBlock; - static vector vNewBlock; - static CReserveKey reservekey(pwalletMain); - - if (params.size() == 0) - { - // Update block - static unsigned int nTransactionsUpdatedLast; - static CBlockIndex* pindexPrev; - static int64 nStart; - static CBlock* pblock; - if (pindexPrev != pindexBest || - (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) - { - if (pindexPrev != pindexBest) - { - // Deallocate old blocks since they're obsolete now - mapNewBlock.clear(); - BOOST_FOREACH(CBlock* pblock, vNewBlock) - delete pblock; - vNewBlock.clear(); - } - nTransactionsUpdatedLast = nTransactionsUpdated; - pindexPrev = pindexBest; - nStart = GetTime(); - - // Create new block - pblock = CreateNewBlock(reservekey); - if (!pblock) - throw JSONRPCError(-7, "Out of memory"); - vNewBlock.push_back(pblock); - } - - // Update nTime - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - pblock->nNonce = 0; - - // Update nExtraNonce - static unsigned int nExtraNonce = 0; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - // Save - mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); - - // Prebuild hash buffers - char pmidstate[32]; - char pdata[128]; - char phash1[64]; - FormatHashBuffers(pblock, pmidstate, pdata, phash1); - - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - - CTransaction coinbaseTx = pblock->vtx[0]; - std::vector merkle = pblock->GetMerkleBranch(0); - - Object result; - result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); - result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); - - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << coinbaseTx; - result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end()))); - - Array merkle_arr; - printf("DEBUG: merkle size %i\n", merkle.size()); - - BOOST_FOREACH(uint256 merkleh, merkle) { - printf("%s\n", merkleh.ToString().c_str()); - merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh))); - } - - result.push_back(Pair("merkle", merkle_arr)); - - - return result; - } - else - { - // Parse parameters - vector vchData = ParseHex(params[0].get_str()); - vector coinbase; - - if(params.size() == 2) - coinbase = ParseHex(params[1].get_str()); - - if (vchData.size() != 128) - throw JSONRPCError(-8, "Invalid parameter"); - - CBlock* pdata = (CBlock*)&vchData[0]; - - // Byte reverse - for (int i = 0; i < 128/4; i++) - ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); - - // Get saved block - if (!mapNewBlock.count(pdata->hashMerkleRoot)) - return false; - CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; - - pblock->nTime = pdata->nTime; - pblock->nNonce = pdata->nNonce; - - if(coinbase.size() == 0) - pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; - else - CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK! - - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - - return CheckWork(pblock, *pwalletMain, reservekey); - } -} - -Value getwork(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getwork [data]\n" - "If [data] is not specified, returns formatted hash data to work on:\n" - " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated - " \"data\" : block data\n" - " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated - " \"target\" : little endian hash target\n" - "If [data] is specified, tries to solve the block and returns true if it was successful."); - - if (vNodes.empty()) - throw JSONRPCError(-9, "CasinoCoin is not connected!"); - - if (IsInitialBlockDownload()) - throw JSONRPCError(-10, "CasinoCoin is downloading blocks..."); - - typedef map > mapNewBlock_t; - static mapNewBlock_t mapNewBlock; // FIXME: thread safety - static vector vNewBlock; - static CReserveKey reservekey(pwalletMain); - - if (params.size() == 0) - { - // Update block - static unsigned int nTransactionsUpdatedLast; - static CBlockIndex* pindexPrev; - static int64 nStart; - static CBlock* pblock; - if (pindexPrev != pindexBest || - (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) - { - if (pindexPrev != pindexBest) - { - // Deallocate old blocks since they're obsolete now - mapNewBlock.clear(); - BOOST_FOREACH(CBlock* pblock, vNewBlock) - delete pblock; - vNewBlock.clear(); - } - nTransactionsUpdatedLast = nTransactionsUpdated; - pindexPrev = pindexBest; - nStart = GetTime(); - - // Create new block - pblock = CreateNewBlock(reservekey); - if (!pblock) - throw JSONRPCError(-7, "Out of memory"); - vNewBlock.push_back(pblock); - } - - // Update nTime - pblock->UpdateTime(pindexPrev); - pblock->nNonce = 0; - - // Update nExtraNonce - static unsigned int nExtraNonce = 0; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - // Save - mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); - - // Prebuild hash buffers - char pmidstate[32]; - char pdata[128]; - char phash1[64]; - FormatHashBuffers(pblock, pmidstate, pdata, phash1); - - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - - Object result; - result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated - result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); - result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated - result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); - result.push_back(Pair("algorithm", "scrypt:1024,1,1")); // CasinoCoin: specify that we should use the scrypt algorithm - return result; - } - else - { - // Parse parameters - vector vchData = ParseHex(params[0].get_str()); - if (vchData.size() != 128) - throw JSONRPCError(-8, "Invalid parameter"); - CBlock* pdata = (CBlock*)&vchData[0]; - - // Byte reverse - for (int i = 0; i < 128/4; i++) - ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); - - // Get saved block - if (!mapNewBlock.count(pdata->hashMerkleRoot)) - return false; - CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; - - pblock->nTime = pdata->nTime; - pblock->nNonce = pdata->nNonce; - pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - - return CheckWork(pblock, *pwalletMain, reservekey); - } -} - - -Value getblocktemplate(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getblocktemplate [params]\n" - "If [params] does not contain a \"data\" key, returns data needed to construct a block to work on:\n" - " \"version\" : block version\n" - " \"previousblockhash\" : hash of current highest block\n" - " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n" - " \"coinbaseaux\" : data that should be included in coinbase\n" - " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" - " \"target\" : hash target\n" - " \"mintime\" : minimum timestamp appropriate for next block\n" - " \"curtime\" : current timestamp\n" - " \"mutable\" : list of ways the block template may be changed\n" - " \"noncerange\" : range of valid nonces\n" - " \"sigoplimit\" : limit of sigops in blocks\n" - " \"sizelimit\" : limit of block size\n" - " \"bits\" : compressed target of next block\n" - " \"height\" : height of the next block\n" - "If [params] does contain a \"data\" key, tries to solve the block and returns null if it was successful (and \"rejected\" if not)\n" - "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); - - const Object& oparam = params[0].get_obj(); - std::string strMode; - { - const Value& modeval = find_value(oparam, "mode"); - if (modeval.type() == str_type) - strMode = modeval.get_str(); - else - if (find_value(oparam, "data").type() == null_type) - strMode = "template"; - else - strMode = "submit"; - } - - if (strMode == "template") - { - if (vNodes.empty()) - throw JSONRPCError(-9, "CasinoCoin is not connected!"); - - if (IsInitialBlockDownload()) - throw JSONRPCError(-10, "CasinoCoin is downloading blocks..."); - - static CReserveKey reservekey(pwalletMain); - - // Update block - static unsigned int nTransactionsUpdatedLast; - static CBlockIndex* pindexPrev; - static int64 nStart; - static CBlock* pblock; - if (pindexPrev != pindexBest || - (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) - { - nTransactionsUpdatedLast = nTransactionsUpdated; - pindexPrev = pindexBest; - nStart = GetTime(); - - // Create new block - if(pblock) - delete pblock; - pblock = CreateNewBlock(reservekey); - if (!pblock) - throw JSONRPCError(-7, "Out of memory"); - } - - // Update nTime - pblock->UpdateTime(pindexPrev); - pblock->nNonce = 0; - - Array transactions; - map setTxIndex; - int i = 0; - CTxDB txdb("r"); - BOOST_FOREACH (CTransaction& tx, pblock->vtx) - { - uint256 txHash = tx.GetHash(); - setTxIndex[txHash] = i++; - - if (tx.IsCoinBase()) - continue; - - Object entry; - - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << tx; - entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); - - entry.push_back(Pair("hash", txHash.GetHex())); - - MapPrevTx mapInputs; - map mapUnused; - bool fInvalid = false; - if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) - { - entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut()))); - - Array deps; - BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs) - { - if (setTxIndex.count(inp.first)) - deps.push_back(setTxIndex[inp.first]); - } - entry.push_back(Pair("depends", deps)); - - int64_t nSigOps = tx.GetLegacySigOpCount(); - nSigOps += tx.GetP2SHSigOpCount(mapInputs); - entry.push_back(Pair("sigops", nSigOps)); - } - - transactions.push_back(entry); - } - - Object aux; - aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - - static Array aMutable; - if (aMutable.empty()) - { - aMutable.push_back("time"); - aMutable.push_back("transactions"); - aMutable.push_back("prevblock"); - } - - Object result; - result.push_back(Pair("version", pblock->nVersion)); - 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("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)); - result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); - result.push_back(Pair("curtime", (int64_t)pblock->nTime)); - result.push_back(Pair("bits", HexBits(pblock->nBits))); - result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); - - return result; - } - else - if (strMode == "submit") - { - // Parse parameters - CDataStream ssBlock(ParseHex(find_value(oparam, "data").get_str()), SER_NETWORK, PROTOCOL_VERSION); - CBlock pblock; - ssBlock >> pblock; - - bool fAccepted = ProcessBlock(NULL, &pblock); - - return fAccepted ? Value::null : "rejected"; - } - - throw JSONRPCError(-8, "Invalid mode"); -} - -Value getrawmempool(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getrawmempool\n" - "Returns all transaction ids in memory pool."); - - vector vtxid; - mempool.queryHashes(vtxid); - - Array a; - BOOST_FOREACH(const uint256& hash, vtxid) - a.push_back(hash.ToString()); - - return a; -} - -Value getblockhash(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getblockhash \n" - "Returns hash of block in best-block-chain at ."); - - int nHeight = params[0].get_int(); - if (nHeight < 0 || nHeight > nBestHeight) - throw runtime_error("Block number out of range."); - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hashBestChain]; - while (pblockindex->nHeight > nHeight) - pblockindex = pblockindex->pprev; - return pblockindex->phashBlock->GetHex(); -} - -Value getblock(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getblock \n" - "Returns details of a block with given block-hash."); - - std::string strHash = params[0].get_str(); - uint256 hash(strHash); - - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(-5, "Block not found"); - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; - block.ReadFromDisk(pblockindex, true); - - return blockToJSON(block, pblockindex); -} - - - - - - // // Call Table @@ -2327,64 +196,75 @@ Value getblock(const Array& params, bool fHelp) static const CRPCCommand vRPCCommands[] = -{ // name function safe mode? - // ------------------------ ----------------------- ---------- - { "help", &help, true }, - { "stop", &stop, true }, - { "getblockcount", &getblockcount, true }, - { "getconnectioncount", &getconnectioncount, true }, - { "getpeerinfo", &getpeerinfo, true }, - { "getdifficulty", &getdifficulty, true }, - { "getnetworkhashps", &getnetworkhashps, true }, - { "getgenerate", &getgenerate, true }, - { "setgenerate", &setgenerate, true }, - { "gethashespersec", &gethashespersec, true }, - { "getinfo", &getinfo, true }, - { "getmininginfo", &getmininginfo, true }, - { "getnewaddress", &getnewaddress, true }, - { "getaccountaddress", &getaccountaddress, true }, - { "setaccount", &setaccount, true }, - { "getaccount", &getaccount, false }, - { "getaddressesbyaccount", &getaddressesbyaccount, true }, - { "sendtoaddress", &sendtoaddress, false }, - { "getreceivedbyaddress", &getreceivedbyaddress, false }, - { "getreceivedbyaccount", &getreceivedbyaccount, false }, - { "listreceivedbyaddress", &listreceivedbyaddress, false }, - { "listreceivedbyaccount", &listreceivedbyaccount, false }, - { "backupwallet", &backupwallet, true }, - { "keypoolrefill", &keypoolrefill, true }, - { "walletpassphrase", &walletpassphrase, true }, - { "walletpassphrasechange", &walletpassphrasechange, false }, - { "walletlock", &walletlock, true }, - { "encryptwallet", &encryptwallet, false }, - { "validateaddress", &validateaddress, true }, - { "getbalance", &getbalance, false }, - { "move", &movecmd, false }, - { "sendfrom", &sendfrom, false }, - { "sendmany", &sendmany, false }, - { "addmultisigaddress", &addmultisigaddress, false }, - { "getrawmempool", &getrawmempool, true }, - { "getblock", &getblock, false }, - { "getblockhash", &getblockhash, false }, - { "gettransaction", &gettransaction, false }, - { "listtransactions", &listtransactions, false }, - { "signmessage", &signmessage, false }, - { "verifymessage", &verifymessage, false }, - { "getwork", &getwork, true }, - { "getworkex", &getworkex, true }, - { "listaccounts", &listaccounts, false }, - { "settxfee", &settxfee, false }, - { "setmininput", &setmininput, false }, - { "getblocktemplate", &getblocktemplate, true }, - { "listsinceblock", &listsinceblock, false }, - { "dumpprivkey", &dumpprivkey, false }, - { "importprivkey", &importprivkey, false }, - { "listunspent", &listunspent, false }, - { "getrawtransaction", &getrawtransaction, false }, - { "createrawtransaction", &createrawtransaction, false }, - { "decoderawtransaction", &decoderawtransaction, false }, - { "signrawtransaction", &signrawtransaction, false }, - { "sendrawtransaction", &sendrawtransaction, false }, +{ // name actor (function) okSafeMode threadSafe reqWallet + // ------------------------ ----------------------- ---------- ---------- --------- + { "help", &help, true, true, false }, + { "stop", &stop, true, true, false }, + { "getblockcount", &getblockcount, true, false, false }, + { "getbestblockhash", &getbestblockhash, true, false, false }, + { "getconnectioncount", &getconnectioncount, true, false, false }, + { "getpeerinfo", &getpeerinfo, true, false, false }, + { "addnode", &addnode, true, true, false }, + { "getaddednodeinfo", &getaddednodeinfo, true, true, false }, + { "getdifficulty", &getdifficulty, true, false, false }, + { "getnetworkhashps", &getnetworkhashps, true, false, false }, + { "getgenerate", &getgenerate, true, false, false }, + { "setgenerate", &setgenerate, true, false, true }, + { "gethashespersec", &gethashespersec, true, false, false }, + { "getinfo", &getinfo, true, false, false }, + { "getmininginfo", &getmininginfo, true, false, false }, + { "getnewaddress", &getnewaddress, true, false, true }, + { "getaccountaddress", &getaccountaddress, true, false, true }, + { "setaccount", &setaccount, true, false, true }, + { "getaccount", &getaccount, false, false, true }, + { "getaddressesbyaccount", &getaddressesbyaccount, true, false, true }, + { "sendtoaddress", &sendtoaddress, false, false, true }, + { "getreceivedbyaddress", &getreceivedbyaddress, false, false, true }, + { "getreceivedbyaccount", &getreceivedbyaccount, false, false, true }, + { "listreceivedbyaddress", &listreceivedbyaddress, false, false, true }, + { "listreceivedbyaccount", &listreceivedbyaccount, false, false, true }, + { "backupwallet", &backupwallet, true, false, true }, + { "keypoolrefill", &keypoolrefill, true, false, true }, + { "walletpassphrase", &walletpassphrase, true, false, true }, + { "walletpassphrasechange", &walletpassphrasechange, false, false, true }, + { "walletlock", &walletlock, true, false, true }, + { "encryptwallet", &encryptwallet, false, false, true }, + { "validateaddress", &validateaddress, true, false, false }, + { "getbalance", &getbalance, false, false, true }, + { "move", &movecmd, false, false, true }, + { "sendfrom", &sendfrom, false, false, true }, + { "sendmany", &sendmany, false, false, true }, + { "addmultisigaddress", &addmultisigaddress, false, false, true }, + { "createmultisig", &createmultisig, true, true , false }, + { "getrawmempool", &getrawmempool, true, false, false }, + { "getblock", &getblock, false, false, false }, + { "getblockhash", &getblockhash, false, false, false }, + { "gettransaction", &gettransaction, false, false, true }, + { "listtransactions", &listtransactions, false, false, true }, + { "listaddressgroupings", &listaddressgroupings, false, false, true }, + { "signmessage", &signmessage, false, false, true }, + { "verifymessage", &verifymessage, false, false, false }, + { "getwork", &getwork, true, false, true }, + { "getworkex", &getworkex, true, false, true }, + { "listaccounts", &listaccounts, false, false, true }, + { "settxfee", &settxfee, false, false, true }, + { "getblocktemplate", &getblocktemplate, true, false, false }, + { "submitblock", &submitblock, false, false, false }, + { "setmininput", &setmininput, false, false, false }, + { "listsinceblock", &listsinceblock, false, false, true }, + { "dumpprivkey", &dumpprivkey, true, false, true }, + { "importprivkey", &importprivkey, false, false, true }, + { "listunspent", &listunspent, false, false, true }, + { "getrawtransaction", &getrawtransaction, false, false, false }, + { "createrawtransaction", &createrawtransaction, false, false, false }, + { "decoderawtransaction", &decoderawtransaction, false, false, false }, + { "signrawtransaction", &signrawtransaction, false, false, false }, + { "sendrawtransaction", &sendrawtransaction, false, false, false }, + { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, + { "gettxout", &gettxout, true, false, false }, + { "lockunspent", &lockunspent, false, false, true }, + { "listlockunspent", &listlockunspent, false, false, true }, + { "verifychain", &verifychain, true, false, false }, }; CRPCTable::CRPCTable() @@ -2438,7 +318,7 @@ string rfc1123Time() time(&now); struct tm* now_gmt = gmtime(&now); string locale(setlocale(LC_TIME, NULL)); - setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings + setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt); setlocale(LC_TIME, locale.c_str()); return string(buffer); @@ -2446,7 +326,7 @@ string rfc1123Time() static string HTTPReply(int nStatus, const string& strMsg, bool keepalive) { - if (nStatus == 401) + if (nStatus == HTTP_UNAUTHORIZED) return strprintf("HTTP/1.0 401 Authorization Required\r\n" "Date: %s\r\n" "Server: casinocoin-json-rpc/%s\r\n" @@ -2464,17 +344,17 @@ static string HTTPReply(int nStatus, const string& strMsg, bool keepalive) "

401 Unauthorized.

\r\n" "\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str()); const char *cStatus; - if (nStatus == 200) cStatus = "OK"; - else if (nStatus == 400) cStatus = "Bad Request"; - else if (nStatus == 403) cStatus = "Forbidden"; - else if (nStatus == 404) cStatus = "Not Found"; - else if (nStatus == 500) cStatus = "Internal Server Error"; + if (nStatus == HTTP_OK) cStatus = "OK"; + else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request"; + else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden"; + else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found"; + else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error"; else cStatus = ""; return strprintf( "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" "Connection: %s\r\n" - "Content-Length: %d\r\n" + "Content-Length: %"PRIszu"\r\n" "Content-Type: application/json\r\n" "Server: casinocoin-json-rpc/%s\r\n" "\r\n" @@ -2488,6 +368,41 @@ static string HTTPReply(int nStatus, const string& strMsg, bool keepalive) strMsg.c_str()); } +bool ReadHTTPRequestLine(std::basic_istream& stream, int &proto, + string& http_method, string& http_uri) +{ + string str; + getline(stream, str); + + // HTTP request line is space-delimited + vector vWords; + boost::split(vWords, str, boost::is_any_of(" ")); + if (vWords.size() < 2) + return false; + + // HTTP methods permitted: GET, POST + http_method = vWords[0]; + if (http_method != "GET" && http_method != "POST") + return false; + + // HTTP URI must be an absolute path, relative to current host + http_uri = vWords[1]; + if (http_uri.size() == 0 || http_uri[0] != '/') + return false; + + // parse proto, if present + string strProto = ""; + if (vWords.size() > 2) + strProto = vWords[2]; + + proto = 0; + const char *ver = strstr(strProto.c_str(), "HTTP/1."); + if (ver != NULL) + proto = atoi(ver+7); + + return true; +} + int ReadHTTPStatus(std::basic_istream& stream, int &proto) { string str; @@ -2495,7 +410,7 @@ int ReadHTTPStatus(std::basic_istream& stream, int &proto) vector vWords; boost::split(vWords, str, boost::is_any_of(" ")); if (vWords.size() < 2) - return 500; + return HTTP_INTERNAL_SERVER_ERROR; proto = 0; const char *ver = strstr(str.c_str(), "HTTP/1."); if (ver != NULL) @@ -2503,7 +418,7 @@ int ReadHTTPStatus(std::basic_istream& stream, int &proto) return atoi(vWords[1].c_str()); } -int ReadHTTPHeader(std::basic_istream& stream, map& mapHeadersRet) +int ReadHTTPHeaders(std::basic_istream& stream, map& mapHeadersRet) { int nLen = 0; loop @@ -2528,19 +443,17 @@ int ReadHTTPHeader(std::basic_istream& stream, map& mapHea return nLen; } -int ReadHTTP(std::basic_istream& stream, map& mapHeadersRet, string& strMessageRet) +int ReadHTTPMessage(std::basic_istream& stream, map& mapHeadersRet, string& strMessageRet, + int nProto) { mapHeadersRet.clear(); strMessageRet = ""; - // Read status - int nProto = 0; - int nStatus = ReadHTTPStatus(stream, nProto); - // Read header - int nLen = ReadHTTPHeader(stream, mapHeadersRet); + int nLen = ReadHTTPHeaders(stream, mapHeadersRet); if (nLen < 0 || nLen > (int)MAX_SIZE) - return 500; + return HTTP_INTERNAL_SERVER_ERROR; // Read message if (nLen > 0) @@ -2560,7 +473,7 @@ int ReadHTTP(std::basic_istream& stream, map& mapHeadersRe mapHeadersRet["connection"] = "close"; } - return nStatus; + return HTTP_OK; } bool HTTPAuthorized(map& mapHeaders) @@ -2570,11 +483,11 @@ bool HTTPAuthorized(map& mapHeaders) return false; string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); string strUserPass = DecodeBase64(strUserPass64); - return strUserPass == strRPCUserColonPass; + return TimingResistantEqual(strUserPass, strRPCUserColonPass); } // -// JSON-RPC protocol. CasinoCoin speaks version 1.0 for maximum compatibility, +// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were // unspecified (HTTP errors and contents of 'error'). // @@ -2613,10 +526,10 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id) void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) { // Send error reply from json-rpc error object - int nStatus = 500; + int nStatus = HTTP_INTERNAL_SERVER_ERROR; int code = find_value(objError, "code").get_int(); - if (code == -32600) nStatus = 400; - else if (code == -32601) nStatus = 404; + if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; + else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND; string strReply = JSONRPCReply(Value::null, objError, id); stream << HTTPReply(nStatus, strReply, false) << std::flush; } @@ -2632,7 +545,7 @@ bool ClientAllowed(const boost::asio::ip::address& address) if (address == asio::ip::address_v4::loopback() || address == asio::ip::address_v6::loopback() || (address.is_v4() - // Chech whether IPv4 addresses match 127.0.0.0/8 (loopback subnet) + // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet) && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000)) return true; @@ -2744,28 +657,7 @@ private: iostreams::stream< SSLIOStreamDevice > _stream; }; -void ThreadRPCServer(void* parg) -{ - IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg)); - - // Make this thread recognisable as the RPC listener - RenameThread("bitcoin-rpclist"); - - try - { - vnThreadsRunning[THREAD_RPCLISTENER]++; - ThreadRPCServer2(parg); - vnThreadsRunning[THREAD_RPCLISTENER]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_RPCLISTENER]--; - PrintException(&e, "ThreadRPCServer()"); - } catch (...) { - vnThreadsRunning[THREAD_RPCLISTENER]--; - PrintException(NULL, "ThreadRPCServer()"); - } - printf("ThreadRPCServer exited\n"); -} +void ServiceConnection(AcceptedConnection *conn); // Forward declaration required for RPCListen template @@ -2807,11 +699,8 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptoris_open()) + // Immediately start accepting new connections, except when we're cancelled or our socket is closed. + if (error != asio::error::operation_aborted && acceptor->is_open()) RPCListen(acceptor, context, fUseSSL); AcceptedConnectionImpl* tcp_conn = dynamic_cast< AcceptedConnectionImpl* >(conn); @@ -2825,30 +714,25 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptorpeer.address())) + else if (tcp_conn && !ClientAllowed(tcp_conn->peer.address())) { // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake. if (!fUseSSL) - conn->stream() << HTTPReply(403, "", false) << std::flush; + conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; delete conn; } - - // start HTTP client thread - else if (!CreateThread(ThreadRPCServer3, conn)) { - printf("Failed to create RPC server client thread\n"); + else { + ServiceConnection(conn); + conn->close(); delete conn; } - - vnThreadsRunning[THREAD_RPCLISTENER]--; } -void ThreadRPCServer2(void* parg) +void StartRPCThreads() { - printf("ThreadRPCServer started\n"); - strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; - if (mapArgs["-rpcpassword"] == "") + if ((mapArgs["-rpcpassword"] == "") || + (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) { unsigned char rand_pwd[32]; RAND_bytes(rand_pwd, 32); @@ -2858,51 +742,54 @@ void ThreadRPCServer2(void* parg) else if (mapArgs.count("-daemon")) strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); uiInterface.ThreadSafeMessageBox(strprintf( - _("%s, you must set a rpcpassword in the configuration file:\n %s\n" + _("%s, you must set a rpcpassword in the configuration file:\n" + "%s\n" "It is recommended you use the following random password:\n" "rpcuser=casinocoinrpc\n" "rpcpassword=%s\n" "(you do not need to remember this password)\n" - "If the file does not exist, create it with owner-readable-only file permissions.\n"), + "The username and password MUST NOT be the same.\n" + "If the file does not exist, create it with owner-readable-only file permissions.\n" + "It is also recommended to set alertnotify so you are notified of problems;\n" + "for example: alertnotify=echo %%s | mail -s \"CasinoCoin Alert\" admin@foo.com\n"), strWhatAmI.c_str(), GetConfigFile().string().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), - _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + "", CClientUIInterface::MSG_ERROR); StartShutdown(); return; } + assert(rpc_io_service == NULL); + rpc_io_service = new asio::io_service(); + rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23); + const bool fUseSSL = GetBoolArg("-rpcssl"); - asio::io_service io_service; - - ssl::context context(io_service, ssl::context::sslv23); if (fUseSSL) { - context.set_options(ssl::context::no_sslv2); + rpc_ssl_context->set_options(ssl::context::no_sslv2); filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert")); if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile; - if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string()); + if (filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string()); else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str()); filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem")); if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile; - if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem); + if (filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem); else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str()); string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"); - SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str()); + SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str()); } // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets const bool loopback = !mapArgs.count("-rpcallowip"); asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any(); - ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 47970)); + ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", GetDefaultRPCPort())); boost::system::error_code v6_only_error; - boost::shared_ptr acceptor(new ip::tcp::acceptor(io_service)); - - boost::signals2::signal StopRequests; + boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); bool fListening = false; std::string strerr; @@ -2917,17 +804,13 @@ void ThreadRPCServer2(void* parg) acceptor->bind(endpoint); acceptor->listen(socket_base::max_connections); - RPCListen(acceptor, context, fUseSSL); - // Cancel outstanding listen-requests for this acceptor when shutting down - StopRequests.connect(signals2::slot( - static_cast(&ip::tcp::acceptor::close), acceptor.get()) - .track(acceptor)); + RPCListen(acceptor, *rpc_ssl_context, fUseSSL); fListening = true; } catch(boost::system::system_error &e) { - strerr = strprintf(_("An error occurred while setting up the RPC port %i for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what()); + strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what()); } try { @@ -2937,38 +820,42 @@ void ThreadRPCServer2(void* parg) bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any(); endpoint.address(bindAddress); - acceptor.reset(new ip::tcp::acceptor(io_service)); + acceptor.reset(new ip::tcp::acceptor(*rpc_io_service)); acceptor->open(endpoint.protocol()); acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); acceptor->bind(endpoint); acceptor->listen(socket_base::max_connections); - RPCListen(acceptor, context, fUseSSL); - // Cancel outstanding listen-requests for this acceptor when shutting down - StopRequests.connect(signals2::slot( - static_cast(&ip::tcp::acceptor::close), acceptor.get()) - .track(acceptor)); + RPCListen(acceptor, *rpc_ssl_context, fUseSSL); fListening = true; - } } catch(boost::system::system_error &e) { - strerr = strprintf(_("An error occurred while setting up the RPC port %i for listening on IPv4: %s"), endpoint.port(), e.what()); + strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv4: %s"), endpoint.port(), e.what()); } if (!fListening) { - uiInterface.ThreadSafeMessageBox(strerr, _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return; } - vnThreadsRunning[THREAD_RPCLISTENER]--; - while (!fShutdown) - io_service.run_one(); - vnThreadsRunning[THREAD_RPCLISTENER]++; - StopRequests(); + rpc_worker_group = new boost::thread_group(); + for (int i = 0; i < GetArg("-rpcthreads", 4); i++) + rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); +} + +void StopRPCThreads() +{ + if (rpc_io_service == NULL) return; + + rpc_io_service->stop(); + rpc_worker_group->join_all(); + delete rpc_worker_group; rpc_worker_group = NULL; + delete rpc_ssl_context; rpc_ssl_context = NULL; + delete rpc_io_service; rpc_io_service = NULL; } class JSONRequest @@ -2986,7 +873,7 @@ void JSONRequest::parse(const Value& valRequest) { // Parse request if (valRequest.type() != obj_type) - throw JSONRPCError(-32600, "Invalid Request object"); + throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); const Object& request = valRequest.get_obj(); // Parse id now so errors from here on will have the id @@ -2995,11 +882,11 @@ void JSONRequest::parse(const Value& valRequest) // Parse method Value valMethod = find_value(request, "method"); if (valMethod.type() == null_type) - throw JSONRPCError(-32600, "Missing method"); + throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); if (valMethod.type() != str_type) - throw JSONRPCError(-32600, "Method must be a string"); + throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); strMethod = valMethod.get_str(); - if (strMethod != "getwork" && strMethod != "getblocktemplate") + if (strMethod != "getwork" && strMethod != "getworkex" && strMethod != "getblocktemplate") printf("ThreadRPCServer method=%s\n", strMethod.c_str()); // Parse params @@ -3009,7 +896,7 @@ void JSONRequest::parse(const Value& valRequest) else if (valParams.type() == null_type) params = Array(); else - throw JSONRPCError(-32600, "Params must be an array"); + throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); } static Object JSONRPCExecOne(const Value& req) @@ -3030,7 +917,7 @@ static Object JSONRPCExecOne(const Value& req) catch (std::exception& e) { rpc_result = JSONRPCReplyObj(Value::null, - JSONRPCError(-32700, e.what()), jreq.id); + JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); } return rpc_result; @@ -3045,42 +932,31 @@ static string JSONRPCExecBatch(const Array& vReq) return write_string(Value(ret), false) + "\n"; } -static CCriticalSection cs_THREAD_RPCHANDLER; - -void ThreadRPCServer3(void* parg) +void ServiceConnection(AcceptedConnection *conn) { - IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer3(parg)); - - // Make this thread recognisable as the RPC handler - RenameThread("bitcoin-rpchand"); - - { - LOCK(cs_THREAD_RPCHANDLER); - vnThreadsRunning[THREAD_RPCHANDLER]++; - } - AcceptedConnection *conn = (AcceptedConnection *) parg; - bool fRun = true; - loop { - if (fShutdown || !fRun) - { - conn->close(); - delete conn; - { - LOCK(cs_THREAD_RPCHANDLER); - --vnThreadsRunning[THREAD_RPCHANDLER]; - } - return; - } + while (fRun) + { + int nProto = 0; map mapHeaders; - string strRequest; + string strRequest, strMethod, strURI; - ReadHTTP(conn->stream(), mapHeaders, strRequest); + // Read HTTP request line + if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI)) + break; + + // Read HTTP message headers and body + ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto); + + if (strURI != "/") { + conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; + break; + } // Check authorization if (mapHeaders.count("authorization") == 0) { - conn->stream() << HTTPReply(401, "", false) << std::flush; + conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; break; } if (!HTTPAuthorized(mapHeaders)) @@ -3090,9 +966,9 @@ void ThreadRPCServer3(void* parg) If this results in a DOS the user really shouldn't have their RPC port exposed.*/ if (mapArgs["-rpcpassword"].size() < 20) - Sleep(250); + MilliSleep(250); - conn->stream() << HTTPReply(401, "", false) << std::flush; + conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; break; } if (mapHeaders["connection"] == "close") @@ -3104,7 +980,7 @@ void ThreadRPCServer3(void* parg) // Parse request Value valRequest; if (!read_string(strRequest, valRequest)) - throw JSONRPCError(-32700, "Parse error"); + throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); string strReply; @@ -3121,9 +997,9 @@ void ThreadRPCServer3(void* parg) } else if (valRequest.type() == array_type) strReply = JSONRPCExecBatch(valRequest.get_array()); else - throw JSONRPCError(-32700, "Top-level object parse error"); - - conn->stream() << HTTPReply(200, strReply, fRun) << std::flush; + throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); + + conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush; } catch (Object& objError) { @@ -3132,16 +1008,10 @@ void ThreadRPCServer3(void* parg) } catch (std::exception& e) { - ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), jreq.id); + ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); break; } } - - delete conn; - { - LOCK(cs_THREAD_RPCHANDLER); - vnThreadsRunning[THREAD_RPCHANDLER]--; - } } json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array ¶ms) const @@ -3149,27 +1019,36 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s // Find method const CRPCCommand *pcmd = tableRPC[strMethod]; if (!pcmd) - throw JSONRPCError(-32601, "Method not found"); + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); + if (pcmd->reqWallet && !pwalletMain) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); // Observe safe mode string strWarning = GetWarnings("rpc"); if (strWarning != "" && !GetBoolArg("-disablesafemode") && !pcmd->okSafeMode) - throw JSONRPCError(-2, string("Safe mode: ") + strWarning); + throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); try { // Execute Value result; { - LOCK2(cs_main, pwalletMain->cs_wallet); - result = pcmd->actor(params, false); + if (pcmd->threadSafe) + result = pcmd->actor(params, false); + else if (!pwalletMain) { + LOCK(cs_main); + result = pcmd->actor(params, false); + } else { + LOCK2(cs_main, pwalletMain->cs_wallet); + result = pcmd->actor(params, false); + } } return result; } catch (std::exception& e) { - throw JSONRPCError(-1, e.what()); + throw JSONRPCError(RPC_MISC_ERROR, e.what()); } } @@ -3190,7 +1069,7 @@ Object CallRPC(const string& strMethod, const Array& params) asio::ssl::stream sslStream(io_service, context); SSLIOStreamDevice d(sslStream, fUseSSL); iostreams::stream< SSLIOStreamDevice > stream(d); - if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "47970"))) + if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(GetDefaultRPCPort())))) throw runtime_error("couldn't connect to server"); // HTTP basic authentication @@ -3203,13 +1082,18 @@ Object CallRPC(const string& strMethod, const Array& params) string strPost = HTTPPost(strRequest, mapRequestHeaders); stream << strPost << std::flush; - // Receive reply + // Receive HTTP reply status + int nProto = 0; + int nStatus = ReadHTTPStatus(stream, nProto); + + // Receive HTTP reply message headers and body map mapHeaders; string strReply; - int nStatus = ReadHTTP(stream, mapHeaders, strReply); - if (nStatus == 401) + ReadHTTPMessage(stream, mapHeaders, strReply, nProto); + + if (nStatus == HTTP_UNAUTHORIZED) throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); - else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500) + else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR) throw runtime_error(strprintf("server returned HTTP error %d", nStatus)); else if (strReply.empty()) throw runtime_error("no response from server"); @@ -3229,8 +1113,10 @@ Object CallRPC(const string& strMethod, const Array& params) template -void ConvertTo(Value& value) +void ConvertTo(Value& value, bool fAllowNull=false) { + if (fAllowNull && value.type() == null_type) + return; if (value.type() == str_type) { // reinterpret string as unquoted json value @@ -3238,7 +1124,8 @@ void ConvertTo(Value& value) string strJSON = value.get_str(); if (!read_string(strJSON, value2)) throw runtime_error(string("Error parsing JSON:")+strJSON); - value = value2.get_value(); + ConvertTo(value2, fAllowNull); + value = value2; } else { @@ -3258,8 +1145,12 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 0) ConvertTo(params[0]); + if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo(params[0]); if (strMethod == "setgenerate" && n > 0) ConvertTo(params[0]); if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); + if (strMethod == "getnetworkhashps" && n > 0) ConvertTo(params[0]); + if (strMethod == "getnetworkhashps" && n > 1) ConvertTo(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "settxfee" && n > 0) ConvertTo(params[0]); if (strMethod == "setmininput" && n > 0) ConvertTo(params[0]); @@ -3285,13 +1176,24 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 2) ConvertTo(params[2]); if (strMethod == "addmultisigaddress" && n > 0) ConvertTo(params[0]); if (strMethod == "addmultisigaddress" && n > 1) ConvertTo(params[1]); + if (strMethod == "createmultisig" && n > 0) ConvertTo(params[0]); + if (strMethod == "createmultisig" && n > 1) ConvertTo(params[1]); if (strMethod == "listunspent" && n > 0) ConvertTo(params[0]); if (strMethod == "listunspent" && n > 1) ConvertTo(params[1]); + if (strMethod == "listunspent" && n > 2) ConvertTo(params[2]); + if (strMethod == "getblock" && n > 1) ConvertTo(params[1]); if (strMethod == "getrawtransaction" && n > 1) ConvertTo(params[1]); if (strMethod == "createrawtransaction" && n > 0) ConvertTo(params[0]); if (strMethod == "createrawtransaction" && n > 1) ConvertTo(params[1]); - if (strMethod == "signrawtransaction" && n > 1) ConvertTo(params[1]); - if (strMethod == "signrawtransaction" && n > 2) ConvertTo(params[2]); + if (strMethod == "signrawtransaction" && n > 1) ConvertTo(params[1], true); + if (strMethod == "signrawtransaction" && n > 2) ConvertTo(params[2], true); + if (strMethod == "gettxout" && n > 1) ConvertTo(params[1]); + if (strMethod == "gettxout" && n > 2) ConvertTo(params[2]); + if (strMethod == "lockunspent" && n > 0) ConvertTo(params[0]); + if (strMethod == "lockunspent" && n > 1) ConvertTo(params[1]); + if (strMethod == "importprivkey" && n > 2) ConvertTo(params[2]); + if (strMethod == "verifychain" && n > 0) ConvertTo(params[0]); + if (strMethod == "verifychain" && n > 1) ConvertTo(params[1]); return params; } @@ -3343,13 +1245,14 @@ int CommandLineRPC(int argc, char *argv[]) strPrint = write_string(result, true); } } - catch (std::exception& e) - { + catch (boost::thread_interrupted) { + throw; + } + catch (std::exception& e) { strPrint = string("error: ") + e.what(); nRet = 87; } - catch (...) - { + catch (...) { PrintException(NULL, "CommandLineRPC()"); } @@ -3367,7 +1270,7 @@ int CommandLineRPC(int argc, char *argv[]) int main(int argc, char *argv[]) { #ifdef _MSC_VER - // Turn off microsoft heap dump noise + // Turn off Microsoft heap dump noise _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); #endif @@ -3387,6 +1290,9 @@ int main(int argc, char *argv[]) return CommandLineRPC(argc, argv); } } + catch (boost::thread_interrupted) { + throw; + } catch (std::exception& e) { PrintException(&e, "main()"); } catch (...) { diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 4b84272..bea7712 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -1,7 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,13 +10,66 @@ #include #include +class CBlockIndex; +class CReserveKey; + #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" #include "json/json_spirit_utils.h" +#include "util.h" + +// HTTP status codes +enum HTTPStatusCode +{ + HTTP_OK = 200, + HTTP_BAD_REQUEST = 400, + HTTP_UNAUTHORIZED = 401, + HTTP_FORBIDDEN = 403, + HTTP_NOT_FOUND = 404, + HTTP_INTERNAL_SERVER_ERROR = 500, +}; + +// Bitcoin RPC error codes +enum RPCErrorCode +{ + // Standard JSON-RPC 2.0 errors + RPC_INVALID_REQUEST = -32600, + RPC_METHOD_NOT_FOUND = -32601, + RPC_INVALID_PARAMS = -32602, + 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 + + // P2P client errors + RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected + RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, // Still downloading initial blocks + + // 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 +}; + json_spirit::Object JSONRPCError(int code, const std::string& message); -void ThreadRPCServer(void* parg); +void StartRPCThreads(); +void StopRPCThreads(); int CommandLineRPC(int argc, char *argv[]); /** Convert parameter values for RPC call from strings to command-specific JSON objects. */ @@ -30,13 +81,13 @@ json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vec Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); */ void RPCTypeCheck(const json_spirit::Array& params, - const std::list& typesExpected); + const std::list& typesExpected, bool fAllowNull=false); /* Check for expected keys/value types in an Object. Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type)); */ void RPCTypeCheck(const json_spirit::Object& o, - const std::map& typesExpected); + const std::map& typesExpected, bool fAllowNull=false); typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); @@ -46,6 +97,8 @@ public: std::string name; rpcfn_type actor; bool okSafeMode; + bool threadSafe; + bool reqWallet; }; /** @@ -72,4 +125,85 @@ public: extern const CRPCTable tableRPC; +extern void InitRPCMining(); +extern void ShutdownRPCMining(); + +extern int64 nWalletUnlockTime; +extern int64 AmountFromValue(const json_spirit::Value& value); +extern json_spirit::Value ValueFromAmount(int64 amount); +extern double GetDifficulty(const CBlockIndex* blockindex = NULL); +extern std::string HexBits(unsigned int nBits); +extern std::string HelpRequiringPassphrase(); +extern void EnsureWalletIsUnlocked(); + +extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp +extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp +extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp +extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getworkex(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp +extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value setaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getaddressesbyaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendtoaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value signmessage(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value verifymessage(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getreceivedbyaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getreceivedbyaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getbalance(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value backupwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value keypoolrefill(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value walletpassphrase(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value walletpassphrasechange(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value walletlock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value encryptwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value validateaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp +extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp +extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value setmininput(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp); + #endif diff --git a/src/bloom.cpp b/src/bloom.cpp new file mode 100644 index 0000000..6bdffdb --- /dev/null +++ b/src/bloom.cpp @@ -0,0 +1,182 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include + +#include "bloom.h" +#include "main.h" +#include "script.h" + +#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455 +#define LN2 0.6931471805599453094172321214581765680755001343602552 + +using namespace std; + +static const unsigned char bit_mask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; + +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), +// 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 http://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)), +nTweak(nTweakIn), +nFlags(nFlagsIn) +{ +} + +inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector& vDataToHash) const +{ + // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values. + return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8); +} + +void CBloomFilter::insert(const vector& vKey) +{ + if (isFull) + return; + for (unsigned int i = 0; i < nHashFuncs; i++) + { + unsigned int nIndex = Hash(i, vKey); + // Sets bit nIndex of vData + vData[nIndex >> 3] |= bit_mask[7 & nIndex]; + } + isEmpty = false; +} + +void CBloomFilter::insert(const COutPoint& outpoint) +{ + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << outpoint; + vector data(stream.begin(), stream.end()); + insert(data); +} + +void CBloomFilter::insert(const uint256& hash) +{ + vector data(hash.begin(), hash.end()); + insert(data); +} + +bool CBloomFilter::contains(const vector& vKey) const +{ + if (isFull) + return true; + if (isEmpty) + return false; + for (unsigned int i = 0; i < nHashFuncs; i++) + { + unsigned int nIndex = Hash(i, vKey); + // Checks bit nIndex of vData + if (!(vData[nIndex >> 3] & bit_mask[7 & nIndex])) + return false; + } + return true; +} + +bool CBloomFilter::contains(const COutPoint& outpoint) const +{ + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << outpoint; + vector data(stream.begin(), stream.end()); + return contains(data); +} + +bool CBloomFilter::contains(const uint256& hash) const +{ + vector data(hash.begin(), hash.end()); + return contains(data); +} + +bool CBloomFilter::IsWithinSizeConstraints() const +{ + return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS; +} + +bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash) +{ + bool fFound = false; + // Match if the filter contains the hash of tx + // for finding tx when they appear in a block + if (isFull) + return true; + if (isEmpty) + return false; + if (contains(hash)) + fFound = true; + + for (unsigned int i = 0; i < tx.vout.size(); i++) + { + const CTxOut& txout = tx.vout[i]; + // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx + // If this matches, also add the specific output that was matched. + // 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 data; + while (pc < txout.scriptPubKey.end()) + { + opcodetype opcode; + if (!txout.scriptPubKey.GetOp(pc, opcode, data)) + break; + if (data.size() != 0 && contains(data)) + { + fFound = true; + if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL) + insert(COutPoint(hash, i)); + else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY) + { + txnouttype type; + vector > vSolutions; + if (Solver(txout.scriptPubKey, type, vSolutions) && + (type == TX_PUBKEY || type == TX_MULTISIG)) + insert(COutPoint(hash, i)); + } + break; + } + } + } + + if (fFound) + return true; + + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + // Match if the filter contains an outpoint tx spends + if (contains(txin.prevout)) + return true; + + // Match if the filter contains any arbitrary script data element in any scriptSig in tx + CScript::const_iterator pc = txin.scriptSig.begin(); + vector data; + while (pc < txin.scriptSig.end()) + { + opcodetype opcode; + if (!txin.scriptSig.GetOp(pc, opcode, data)) + break; + if (data.size() != 0 && contains(data)) + return true; + } + } + + return false; +} + +void CBloomFilter::UpdateEmptyFull() +{ + bool full = true; + bool empty = true; + for (unsigned int i = 0; i < vData.size(); i++) + { + full &= vData[i] == 0xff; + empty &= vData[i] == 0; + } + isFull = full; + isEmpty = empty; +} diff --git a/src/bloom.h b/src/bloom.h new file mode 100644 index 0000000..f482bfc --- /dev/null +++ b/src/bloom.h @@ -0,0 +1,91 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_BLOOM_H +#define BITCOIN_BLOOM_H + +#include + +#include "uint256.h" +#include "serialize.h" + +class COutPoint; +class CTransaction; + +// 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001% +static const unsigned int MAX_BLOOM_FILTER_SIZE = 36000; // bytes +static const unsigned int MAX_HASH_FUNCS = 50; + +// First two bits of nFlags control how much IsRelevantAndUpdate actually updates +// The remaining bits are reserved +enum bloomflags +{ + BLOOM_UPDATE_NONE = 0, + BLOOM_UPDATE_ALL = 1, + // Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script + BLOOM_UPDATE_P2PUBKEY_ONLY = 2, + BLOOM_UPDATE_MASK = 3, +}; + +/** + * BloomFilter is a probabilistic filter which SPV clients provide + * so that we can filter the transactions we sends them. + * + * This allows for significantly more efficient transaction and block downloads. + * + * Because bloom filters are probabilistic, an SPV node can increase the false- + * positive rate, making us send them transactions which aren't actually theirs, + * allowing clients to trade more bandwidth for more privacy by obfuscating which + * keys are owned by them. + */ +class CBloomFilter +{ +private: + std::vector vData; + bool isFull; + bool isEmpty; + unsigned int nHashFuncs; + unsigned int nTweak; + unsigned char nFlags; + + unsigned int Hash(unsigned int nHashNum, const std::vector& vDataToHash) const; + +public: + // Creates a new bloom filter which will provide the given fp rate when filled with the given number of elements + // Note that if the given parameters will result in a filter outside the bounds of the protocol limits, + // the filter created will be as close to the given parameters as possible within the protocol limits. + // This will apply if nFPRate is very low or nElements is unreasonably high. + // nTweak is a constant which is added to the seed value passed to the hash function + // It should generally always be a random value (and is largely only exposed for unit testing) + // nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK) + CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn); + CBloomFilter() : isFull(true) {} + + IMPLEMENT_SERIALIZE + ( + READWRITE(vData); + READWRITE(nHashFuncs); + READWRITE(nTweak); + READWRITE(nFlags); + ) + + void insert(const std::vector& vKey); + void insert(const COutPoint& outpoint); + void insert(const uint256& hash); + + bool contains(const std::vector& vKey) const; + bool contains(const COutPoint& outpoint) const; + bool contains(const uint256& hash) const; + + // True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS + // (catch a filter which was just deserialized which was too big) + bool IsWithinSizeConstraints() const; + + // Also adds any outputs which match the filter to the filter (to match their spending txes) + bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash); + + // Checks for empty and full filters to avoid wasting cpu + void UpdateEmptyFull(); +}; + +#endif /* BITCOIN_BLOOM_H */ diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 7382266..819818a 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -1,6 +1,4 @@ // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,45 +14,143 @@ namespace Checkpoints { typedef std::map MapCheckpoints; - // + // How many times we expect transactions after the last checkpoint to + // be slower. 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 fSigcheckVerificationFactor = 5.0; + + struct CCheckpointData { + const MapCheckpoints *mapCheckpoints; + int64 nTimeLastCheckpoint; + int64 nTransactionsLastCheckpoint; + double fTransactionsPerDay; + }; + // What makes a good checkpoint block? // + Is surrounded by blocks with reasonable timestamps // (no blocks before with a timestamp after, none after with // timestamp before) // + Contains no strange transactions - // static MapCheckpoints mapCheckpoints = boost::assign::map_list_of - ( 0, uint256("0x4f46c9af6d88a14114b7dc53a37d81ba4064cda5ae2ede1213ca28fea9b86e9c")) - ( 1, uint256("0xd6eea1064e9292f2a38e138bec64797914cff3189fbc6eaa2cc646c1514ccdfe")) - ( 777, uint256("0x838c9d331811479957009c39d2e1e723d47ebd21453b3ad92bcabd6cb5dd6ab1")) - ( 7777, uint256("0x09ab8471911e0f19e19ef09e1ae212b389f6be3e62f0c140d58c27084da08907")) - ( 17777, uint256("0x4dd8c993bdb32b5ff63a1108f86b1cf2b6f3fb3e5a831d3445d944b986addadf")) - ( 27777, uint256("0xea7623cc7d0db290b4f2bf5b1d5cbf477bf0c019b667d21dbc5e82e12adcf3ae")) - ( 37777, uint256("0xced9dadf09278f513337ebbeee11804b794faddf8f759e583a1e39b0839c238a")) + ( 0, uint256("0x4f46c9af6d88a14114b7dc53a37d81ba4064cda5ae2ede1213ca28fea9b86e9c")) + ( 1, uint256("0xd6eea1064e9292f2a38e138bec64797914cff3189fbc6eaa2cc646c1514ccdfe")) + ( 777, uint256("0x838c9d331811479957009c39d2e1e723d47ebd21453b3ad92bcabd6cb5dd6ab1")) + ( 7777, uint256("0x09ab8471911e0f19e19ef09e1ae212b389f6be3e62f0c140d58c27084da08907")) + ( 17777, uint256("0x4dd8c993bdb32b5ff63a1108f86b1cf2b6f3fb3e5a831d3445d944b986addadf")) + ( 27777, uint256("0xea7623cc7d0db290b4f2bf5b1d5cbf477bf0c019b667d21dbc5e82e12adcf3ae")) + ( 37777, uint256("0xced9dadf09278f513337ebbeee11804b794faddf8f759e583a1e39b0839c238a")) + ( 47777, uint256("0xb59586840946941d9fd92dc378e0f2bd5fa4da0ebd0636dc009acc2a0174e048")) + ( 57777, uint256("0xfdf6fa6f606f3b14e7b2084b0e60a80b769c2ae04fbea62d1af78674d3d1ef76")) + ( 67777, uint256("0x5c6732d5ec60454ce68579cf88118923ebdd5dc82b372310bcf7d7303ffddf39")) + ( 77777, uint256("0x4fa19ce5f0a050cbf13b3ad194c39351276a7e587ccdef03fa926429b00a0d44")) + ( 87777, uint256("0x278d5a4d6ee24dfa263e33032ef0496e0e6d43d9f1918dc269dc83c56d29199c")) + ( 97777, uint256("0xf1ab4d14a7a9797d4c22336aea6d83db6a2e5c7f07121d5b67b958e37ea5e384")) + ( 107777, uint256("0x421ac0aed1cfb4226d4936fa0ac93c45cce9c6bec7aca4e329a672d8414b23ec")) + ( 117777, uint256("0x731713bd84c9fd90cebc6c85c56cd071bd0826841fa1ff193250c9dd897650eb")) + ( 127777, uint256("0xd90c1bb94b4aea5dcb4cb4a03de76190e7b1cf2e14fd45dc8a1e317066118491")) + ( 137777, uint256("0x97972ecfc9efd19567f49c96f3bfaad15b3cc63ce0aac1780c1276624e41e9a2")) + ( 147777, uint256("0xe83328402d705d53074cce0deb98f09b9016357063b522d30dbc450d241a073d")) + ( 157777, uint256("0x86b45c6144bcdff90b2846e1669fdd49392e2c9eef6132184afc1a9434ef43a0")) + ( 167777, uint256("0x065a4f24bf79b45353e456e74a75194be95d49bb9fbe2ef0771b0ff4a2c86ac6")) + ( 177777, uint256("0x221fff51bd7a48c300b863ff5edb82dacf893ea908c00c4f6915789bed0d27b2")) + ( 187777, uint256("0xad3c4d3b73493cb9c888b30f550db4fda6a5ff8c6daa20404285e354c3a4c7a1")) + ( 197777, uint256("0x2f9203c38cede6e1c61a69eb43c4f62d8e04ba62a57a7d866f4d715eec033cd4")) + ( 207777, uint256("0x3631874522954f18e6834ad68918dcc060b2712fea7a381e11e10193c6ab2f24")) + ( 217777, uint256("0xc86150e3408be1ca10eb1b94f374ae331c07dec6e2162bf06f5c31d83faa9715")) ; + static const CCheckpointData data = { + &mapCheckpoints, + 1391536800, // * UNIX timestamp of last checkpoint block + 356643, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + 4500.0 // * estimated number of transactions per day after checkpoint + }; + + static MapCheckpoints mapCheckpointsTestnet = + boost::assign::map_list_of + ( 0, uint256("0x")) + ; + static const CCheckpointData dataTestnet = { + &mapCheckpointsTestnet, + 1369685559, + 37581, + 300 + }; + + const CCheckpointData &Checkpoints() { + if (fTestNet) + return dataTestnet; + else + return data; + } bool CheckBlock(int nHeight, const uint256& hash) { if (fTestNet) return true; // Testnet has no checkpoints + if (!GetBoolArg("-checkpoints", true)) + return true; - MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight); - if (i == mapCheckpoints.end()) return true; + const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; + + MapCheckpoints::const_iterator i = checkpoints.find(nHeight); + if (i == checkpoints.end()) return true; return hash == i->second; } + // Guess how far we are in the verification process at the given block index + double GuessVerificationProgress(CBlockIndex *pindex) { + if (pindex==NULL) + return 0.0; + + int64 nNow = time(NULL); + + 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 checkoint, and + // fSigcheckVerificationFactor per transaction after. + + const CCheckpointData &data = Checkpoints(); + + 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->nTime)/86400.0*data.fTransactionsPerDay; + fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor; + fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor; + } + + return fWorkBefore / (fWorkBefore + fWorkAfter); + } + int GetTotalBlocksEstimate() { - if (fTestNet) return 0; + if (fTestNet) return 0; // Testnet has no checkpoints + if (!GetBoolArg("-checkpoints", true)) + return 0; - return mapCheckpoints.rbegin()->first; + const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; + + return checkpoints.rbegin()->first; } CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) { - if (fTestNet) return NULL; + if (fTestNet) return NULL; // Testnet has no checkpoints + if (!GetBoolArg("-checkpoints", true)) + return NULL; - BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) + const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; + + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) { const uint256& hash = i.second; std::map::const_iterator t = mapBlockIndex.find(hash); diff --git a/src/checkpoints.h b/src/checkpoints.h index 662fc13..3d56885 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -1,10 +1,8 @@ // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_CHECKPOINT_H -#define BITCOIN_CHECKPOINT_H +#define BITCOIN_CHECKPOINT_H #include @@ -24,6 +22,8 @@ namespace Checkpoints // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex); + + double GuessVerificationProgress(CBlockIndex *pindex); } #endif diff --git a/src/checkqueue.h b/src/checkqueue.h new file mode 100644 index 0000000..eba424f --- /dev/null +++ b/src/checkqueue.h @@ -0,0 +1,192 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef CHECKQUEUE_H +#define CHECKQUEUE_H + +#include +#include +#include + +#include +#include + +template class CCheckQueueControl; + +/** Queue for verifications that have to be performed. + * The verifications are represented by a type T, which must provide an + * operator(), returning a bool. + * + * One thread (the master) is assumed to push batches of verifications + * onto the queue, where they are processed by N-1 worker threads. When + * the master is done adding work, it temporarily joins the worker pool + * as an N'th worker, until all jobs are done. + */ +template class CCheckQueue { +private: + // Mutex to protect the inner state + boost::mutex mutex; + + // Worker threads block on this when out of work + boost::condition_variable condWorker; + + // Master thread blocks on this when out of work + boost::condition_variable condMaster; + + // The queue of elements to be processed. + // As the order of booleans doesn't matter, it is used as a LIFO (stack) + std::vector queue; + + // The number of workers (including the master) that are idle. + int nIdle; + + // The total number of workers (including the master). + int nTotal; + + // The temporary evaluation result. + bool fAllOk; + + // Number of verifications that haven't completed yet. + // This includes elements that are not anymore in queue, but still in + // worker's own batches. + unsigned int nTodo; + + // Whether we're shutting down. + bool fQuit; + + // The maximum number of elements to be processed in one batch + unsigned int nBatchSize; + + // Internal function that does bulk of the verification work. + bool Loop(bool fMaster = false) { + boost::condition_variable &cond = fMaster ? condMaster : condWorker; + std::vector vChecks; + vChecks.reserve(nBatchSize); + unsigned int nNow = 0; + bool fOk = true; + do { + { + boost::unique_lock lock(mutex); + // first do the clean-up of the previous loop run (allowing us to do it in the same critsect) + if (nNow) { + fAllOk &= fOk; + nTodo -= nNow; + if (nTodo == 0 && !fMaster) + // We processed the last element; inform the master he can exit and return the result + condMaster.notify_one(); + } else { + // first iteration + nTotal++; + } + // logically, the do loop starts here + while (queue.empty()) { + if ((fMaster || fQuit) && nTodo == 0) { + nTotal--; + bool fRet = fAllOk; + // reset the status for new work later + if (fMaster) + fAllOk = true; + // return the current status + return fRet; + } + nIdle++; + cond.wait(lock); // wait + nIdle--; + } + // Decide how many work units to process now. + // * Do not try to do everything at once, but aim for increasingly smaller batches so + // all workers finish approximately simultaneously. + // * Try to account for idle jobs which will instantly start helping. + // * Don't do batches smaller than 1 (duh), or larger than nBatchSize. + nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1))); + vChecks.resize(nNow); + for (unsigned int i = 0; i < nNow; i++) { + // We want the lock on the mutex to be as short as possible, so swap jobs from the global + // queue to the local batch vector instead of copying. + vChecks[i].swap(queue.back()); + queue.pop_back(); + } + // Check whether we need to do work at all + fOk = fAllOk; + } + // execute work + BOOST_FOREACH(T &check, vChecks) + if (fOk) + fOk = check(); + vChecks.clear(); + } while(true); + } + +public: + // Create a new check queue + CCheckQueue(unsigned int nBatchSizeIn) : + nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {} + + // Worker thread + void Thread() { + Loop(); + } + + // Wait until execution finishes, and return whether all evaluations where succesful. + bool Wait() { + return Loop(true); + } + + // Add a batch of checks to the queue + void Add(std::vector &vChecks) { + boost::unique_lock lock(mutex); + BOOST_FOREACH(T &check, vChecks) { + queue.push_back(T()); + check.swap(queue.back()); + } + nTodo += vChecks.size(); + if (vChecks.size() == 1) + condWorker.notify_one(); + else if (vChecks.size() > 1) + condWorker.notify_all(); + } + + ~CCheckQueue() { + } + + friend class CCheckQueueControl; +}; + +/** RAII-style controller object for a CCheckQueue that guarantees the passed + * queue is finished before continuing. + */ +template class CCheckQueueControl { +private: + CCheckQueue *pqueue; + bool fDone; + +public: + CCheckQueueControl(CCheckQueue *pqueueIn) : pqueue(pqueueIn), fDone(false) { + // passed queue is supposed to be unused, or NULL + if (pqueue != NULL) { + assert(pqueue->nTotal == pqueue->nIdle); + assert(pqueue->nTodo == 0); + assert(pqueue->fAllOk == true); + } + } + + bool Wait() { + if (pqueue == NULL) + return true; + bool fRet = pqueue->Wait(); + fDone = true; + return fRet; + } + + void Add(std::vector &vChecks) { + if (pqueue != NULL) + pqueue->Add(vChecks); + } + + ~CCheckQueueControl() { + if (!fDone) + Wait(); + } +}; + +#endif diff --git a/src/clientversion.h b/src/clientversion.h new file mode 100644 index 0000000..e624492 --- /dev/null +++ b/src/clientversion.h @@ -0,0 +1,26 @@ +#ifndef CLIENTVERSION_H +#define CLIENTVERSION_H + +// +// client versioning and copyright year +// + +// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it +#define CLIENT_VERSION_MAJOR 1 +#define CLIENT_VERSION_MINOR 1 +#define CLIENT_VERSION_REVISION 0 +#define CLIENT_VERSION_BUILD 0 + +// Set to true for release, false for prerelease or test build +#define CLIENT_VERSION_IS_RELEASE true + +// Copyright year (2009-this) +// Todo: update this when changing our copyright comments in the source +#define COPYRIGHT_YEAR 2014 + +// Converts the parameter X to a string after macro replacement on X has been performed. +// Don't merge these into one macro! +#define STRINGIZE(X) DO_STRINGIZE(X) +#define DO_STRINGIZE(X) #X + +#endif // CLIENTVERSION_H diff --git a/src/coincontrol.h b/src/coincontrol.h new file mode 100644 index 0000000..236b586 --- /dev/null +++ b/src/coincontrol.h @@ -0,0 +1,57 @@ +#ifndef COINCONTROL_H +#define COINCONTROL_H + +/** Coin Control Features. */ +class CCoinControl +{ +public: + CTxDestination destChange; + + CCoinControl() + { + SetNull(); + } + + void SetNull() + { + destChange = CNoDestination(); + setSelected.clear(); + } + + bool HasSelected() const + { + return (setSelected.size() > 0); + } + + bool IsSelected(const uint256& hash, unsigned int n) const + { + COutPoint outpt(hash, n); + return (setSelected.count(outpt) > 0); + } + + void Select(COutPoint& output) + { + setSelected.insert(output); + } + + void UnSelect(COutPoint& output) + { + setSelected.erase(output); + } + + void UnSelectAll() + { + setSelected.clear(); + } + + void ListSelected(std::vector& vOutpoints) + { + vOutpoints.assign(setSelected.begin(), setSelected.end()); + } + +private: + std::set setSelected; + +}; + +#endif // COINCONTROL_H diff --git a/src/compat.h b/src/compat.h index bf81e33..7062216 100644 --- a/src/compat.h +++ b/src/compat.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef _BITCOIN_COMPAT_H @@ -13,6 +11,7 @@ #ifndef NOMINMAX #define NOMINMAX #endif +#define FD_SETSIZE 1024 // max number of fds in fd_set #include #include #include diff --git a/src/crypter.cpp b/src/crypter.cpp index 72cedfc..32baabd 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -1,6 +1,4 @@ // Copyright (c) 2009-2012 The Bitcoin Developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,12 +17,6 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) return false; - // Try to keep the keydata 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. - mlock(&chKey[0], sizeof chKey); - mlock(&chIV[0], sizeof chIV); - int i = 0; if (nDerivationMethod == 0) i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], @@ -32,8 +24,8 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v if (i != (int)WALLET_CRYPTO_KEY_SIZE) { - memset(&chKey, 0, sizeof chKey); - memset(&chIV, 0, sizeof chIV); + OPENSSL_cleanse(chKey, sizeof(chKey)); + OPENSSL_cleanse(chIV, sizeof(chIV)); return false; } @@ -46,12 +38,6 @@ bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector& vchCiphertext, CKeyingM } -bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_KEY_SIZE); memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); if(!cKeyCrypter.SetKey(vMasterKey, chIV)) return false; - return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext); + return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); } -bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext) +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_KEY_SIZE); diff --git a/src/crypter.h b/src/crypter.h index 0a41f56..4134c1b 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -1,6 +1,4 @@ // Copyright (c) 2009-2012 The Bitcoin Developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef __CRYPTER_H__ @@ -78,25 +76,32 @@ public: void CleanKey() { - memset(&chKey, 0, sizeof chKey); - memset(&chIV, 0, sizeof chIV); - munlock(&chKey, sizeof chKey); - munlock(&chIV, sizeof chIV); + OPENSSL_cleanse(chKey, sizeof(chKey)); + OPENSSL_cleanse(chIV, sizeof(chIV)); 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); } ~CCrypter() { CleanKey(); + + LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey); + LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV); } }; -bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); -bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext); +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); #endif diff --git a/src/db.cpp b/src/db.cpp index 1830f67..2bda065 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1,15 +1,11 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "db.h" #include "util.h" #include "main.h" -#include "init.h" -#include #include #include @@ -37,19 +33,17 @@ void CDBEnv::EnvShutdown() return; fDbEnvInit = false; - try - { - dbenv.close(0); - } - catch (const DbException& e) - { - printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno()); - } - DbEnv(0).remove(GetDataDir().string().c_str(), 0); + int ret = dbenv.close(0); + if (ret != 0) + printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret); + if (!fMockDb) + DbEnv(0).remove(path.string().c_str(), 0); } -CDBEnv::CDBEnv() : dbenv(0) +CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) { + fDbEnvInit = false; + fMockDb = false; } CDBEnv::~CDBEnv() @@ -62,37 +56,34 @@ void CDBEnv::Close() EnvShutdown(); } -bool CDBEnv::Open(boost::filesystem::path pathEnv_) +bool CDBEnv::Open(const boost::filesystem::path& pathIn) { if (fDbEnvInit) return true; - if (fShutdown) - return false; + boost::this_thread::interruption_point(); - pathEnv = pathEnv_; - filesystem::path pathDataDir = pathEnv; - filesystem::path pathLogDir = pathDataDir / "database"; + path = pathIn; + filesystem::path pathLogDir = path / "database"; filesystem::create_directory(pathLogDir); - filesystem::path pathErrorFile = pathDataDir / "db.log"; + filesystem::path pathErrorFile = path / "db.log"; printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); unsigned int nEnvFlags = 0; if (GetBoolArg("-privdb", true)) nEnvFlags |= DB_PRIVATE; - int nDbCache = GetArg("-dbcache", 25); dbenv.set_lg_dir(pathLogDir.string().c_str()); - dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); - dbenv.set_lg_bsize(1048576); - dbenv.set_lg_max(10485760); - dbenv.set_lk_max_locks(537000); - dbenv.set_lk_max_objects(10000); + dbenv.set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet + dbenv.set_lg_bsize(0x10000); + 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_flags(DB_AUTO_COMMIT, 1); dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv.open(pathDataDir.string().c_str(), + int ret = dbenv.open(path.string().c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -102,38 +93,123 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_) DB_RECOVER | nEnvFlags, S_IRUSR | S_IWUSR); - if (ret > 0) - return error("CDB() : error %d opening database environment", ret); - - // Check that the number of locks is sufficient - u_int32_t nMaxLocks; - if (!dbenv.get_lk_max_locks(&nMaxLocks)) - { - int nBlocks, nDeepReorg; - std::string strMessage; - - nBlocks = nMaxLocks / 48768; - nDeepReorg = (nBlocks - 1) / 2; - printf("Final lk_max_locks is %lu, sufficient for (worst case) %d block%s in a single transaction (up to a %d-deep reorganization)\n", (unsigned long)nMaxLocks, nBlocks, (nBlocks == 1) ? "" : "s", nDeepReorg); - if (nDeepReorg < 3) - { - if (nBlocks < 1) - strMessage = strprintf(_("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a single block. If this limit is reached, Bitcoin may stop working."), (unsigned long)nMaxLocks); - else - strMessage = strprintf(_("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a common blockchain reorganization. If this limit is reached, Bitcoin may stop working."), (unsigned long)nMaxLocks); - - strMiscWarning = strMessage; - printf("*** %s\n", strMessage.c_str()); - } - } + if (ret != 0) + return error("CDB() : error %s (%d) opening database environment", DbEnv::strerror(ret), ret); fDbEnvInit = true; + fMockDb = false; return true; } +void CDBEnv::MakeMock() +{ + if (fDbEnvInit) + throw runtime_error("CDBEnv::MakeMock(): already initialized"); + + boost::this_thread::interruption_point(); + + printf("CDBEnv::MakeMock()\n"); + + dbenv.set_cachesize(1, 0, 1); + dbenv.set_lg_bsize(10485760*4); + dbenv.set_lg_max(10485760); + dbenv.set_lk_max_locks(10000); + dbenv.set_lk_max_objects(10000); + dbenv.set_flags(DB_AUTO_COMMIT, 1); + dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); + int ret = dbenv.open(NULL, + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_PRIVATE, + S_IRUSR | S_IWUSR); + if (ret > 0) + throw runtime_error(strprintf("CDBEnv::MakeMock(): error %d opening database environment", ret)); + + fDbEnvInit = true; + fMockDb = true; +} + +CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)) +{ + LOCK(cs_db); + assert(mapFileUseCount.count(strFile) == 0); + + Db db(&dbenv, 0); + int result = db.verify(strFile.c_str(), NULL, NULL, 0); + if (result == 0) + return VERIFY_OK; + else if (recoverFunc == NULL) + return RECOVER_FAIL; + + // Try to recover: + bool fRecovered = (*recoverFunc)(*this, strFile); + return (fRecovered ? RECOVER_OK : RECOVER_FAIL); +} + +bool CDBEnv::Salvage(std::string strFile, bool fAggressive, + std::vector& vResult) +{ + LOCK(cs_db); + assert(mapFileUseCount.count(strFile) == 0); + + u_int32_t flags = DB_SALVAGE; + if (fAggressive) flags |= DB_AGGRESSIVE; + + stringstream strDump; + + Db db(&dbenv, 0); + int result = db.verify(strFile.c_str(), NULL, &strDump, flags); + if (result == DB_VERIFY_BAD) + { + printf("Error: Salvage found errors, all data may not be recoverable.\n"); + if (!fAggressive) + { + printf("Error: Rerun with aggressive mode to ignore errors and continue.\n"); + return false; + } + } + if (result != 0 && result != DB_VERIFY_BAD) + { + printf("ERROR: db salvage failed: %d\n",result); + return false; + } + + // Format of bdb dump is ascii lines: + // header lines... + // HEADER=END + // hexadecimal key + // hexadecimal value + // ... repeated + // DATA=END + + string strLine; + while (!strDump.eof() && strLine != "HEADER=END") + getline(strDump, strLine); // Skip past header + + std::string keyHex, valueHex; + while (!strDump.eof() && keyHex != "DATA=END") + { + getline(strDump, keyHex); + if (keyHex != "DATA_END") + { + getline(strDump, valueHex); + vResult.push_back(make_pair(ParseHex(keyHex),ParseHex(valueHex))); + } + } + + return (result == 0); +} + + void CDBEnv::CheckpointLSN(std::string strFile) { dbenv.txn_checkpoint(0, 0, 0); + if (fMockDb) + return; dbenv.lsn_reset(strFile.c_str(), 0); } @@ -163,21 +239,27 @@ CDB::CDB(const char *pszFile, const char* pszMode) : { pdb = new Db(&bitdb.dbenv, 0); + bool fMockDb = bitdb.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", pszFile)); + } + ret = pdb->open(NULL, // Txn pointer - pszFile, // Filename - "main", // Logical db name + fMockDb ? NULL : pszFile, // Filename + fMockDb ? pszFile : "main", // Logical db name DB_BTREE, // Database type nFlags, // Flags 0); - if (ret > 0) + if (ret != 0) { delete pdb; pdb = NULL; - { - LOCK(bitdb.cs_db); - --bitdb.mapFileUseCount[strFile]; - } + --bitdb.mapFileUseCount[strFile]; strFile = ""; throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret)); } @@ -195,12 +277,17 @@ CDB::CDB(const char *pszFile, const char* pszMode) : } } -static bool IsChainFile(std::string strFile) +void CDB::Flush() { - if (strFile == "blkindex.dat") - return true; + if (activeTxn) + return; - return false; + // Flush database activity from memory pool to disk log + unsigned int nMinutes = 0; + if (fReadOnly) + nMinutes = 1; + + bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); } void CDB::Close() @@ -212,16 +299,7 @@ void CDB::Close() activeTxn = NULL; pdb = NULL; - // Flush database activity from memory pool to disk log - unsigned int nMinutes = 0; - if (fReadOnly) - nMinutes = 1; - if (IsChainFile(strFile)) - nMinutes = 2; - if (IsChainFile(strFile) && IsInitialBlockDownload()) - nMinutes = 5; - - bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); + Flush(); { LOCK(bitdb.cs_db); @@ -244,9 +322,18 @@ 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) { - while (!fShutdown) + while (true) { { LOCK(bitdb.cs_db); @@ -263,7 +350,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); Db* pdbCopy = new Db(&bitdb.dbenv, 0); - + int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename "main", // Logical db name @@ -275,7 +362,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) printf("Cannot create database file %s\n", strFileRes.c_str()); fSuccess = false; } - + Dbc* pcursor = db.GetCursor(); if (pcursor) while (fSuccess) @@ -332,7 +419,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) return fSuccess; } } - Sleep(100); + MilliSleep(100); } return false; } @@ -360,10 +447,9 @@ void CDBEnv::Flush(bool fShutdown) CloseDb(strFile); printf("%s checkpoint\n", strFile.c_str()); dbenv.txn_checkpoint(0, 0, 0); - if (!IsChainFile(strFile) || fDetachDB) { - printf("%s detach\n", strFile.c_str()); + printf("%s detach\n", strFile.c_str()); + if (!fMockDb) dbenv.lsn_reset(strFile.c_str(), 0); - } printf("%s closed\n", strFile.c_str()); mapFileUseCount.erase(mi++); } @@ -378,6 +464,8 @@ void CDBEnv::Flush(bool fShutdown) { dbenv.log_archive(&listp, DB_ARCH_REMOVE); Close(); + if (!fMockDb) + boost::filesystem::remove_all(path / "database"); } } } @@ -388,356 +476,6 @@ void CDBEnv::Flush(bool fShutdown) -// -// CTxDB -// - -bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) -{ - assert(!fClient); - txindex.SetNull(); - return Read(make_pair(string("tx"), hash), txindex); -} - -bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex) -{ - assert(!fClient); - return Write(make_pair(string("tx"), hash), txindex); -} - -bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight) -{ - assert(!fClient); - - // Add to tx index - uint256 hash = tx.GetHash(); - CTxIndex txindex(pos, tx.vout.size()); - return Write(make_pair(string("tx"), hash), txindex); -} - -bool CTxDB::EraseTxIndex(const CTransaction& tx) -{ - assert(!fClient); - uint256 hash = tx.GetHash(); - - return Erase(make_pair(string("tx"), hash)); -} - -bool CTxDB::ContainsTx(uint256 hash) -{ - assert(!fClient); - return Exists(make_pair(string("tx"), hash)); -} - -bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex) -{ - assert(!fClient); - tx.SetNull(); - if (!ReadTxIndex(hash, txindex)) - return false; - return (tx.ReadFromDisk(txindex.pos)); -} - -bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx) -{ - CTxIndex txindex; - return ReadDiskTx(hash, tx, txindex); -} - -bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex) -{ - return ReadDiskTx(outpoint.hash, tx, txindex); -} - -bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx) -{ - CTxIndex txindex; - return ReadDiskTx(outpoint.hash, tx, txindex); -} - -bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) -{ - return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex); -} - -bool CTxDB::ReadHashBestChain(uint256& hashBestChain) -{ - return Read(string("hashBestChain"), hashBestChain); -} - -bool CTxDB::WriteHashBestChain(uint256 hashBestChain) -{ - return Write(string("hashBestChain"), hashBestChain); -} - -bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork) -{ - return Read(string("bnBestInvalidWork"), bnBestInvalidWork); -} - -bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork) -{ - return Write(string("bnBestInvalidWork"), bnBestInvalidWork); -} - -CBlockIndex static * InsertBlockIndex(uint256 hash) -{ - if (hash == 0) - return NULL; - - // Return existing - map::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - return (*mi).second; - - // Create new - CBlockIndex* pindexNew = new CBlockIndex(); - if (!pindexNew) - throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); - mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - - return pindexNew; -} - -bool CTxDB::LoadBlockIndex() -{ - if (!LoadBlockIndexGuts()) - return false; - - if (fRequestShutdown) - return true; - - // Calculate bnChainWork - vector > 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)); - } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) - { - CBlockIndex* pindex = item.second; - pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork(); - } - - // Load hashBestChain pointer to end of best chain - if (!ReadHashBestChain(hashBestChain)) - { - if (pindexGenesisBlock == NULL) - return true; - return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); - } - if (!mapBlockIndex.count(hashBestChain)) - return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); - pindexBest = mapBlockIndex[hashBestChain]; - nBestHeight = pindexBest->nHeight; - bnBestChainWork = pindexBest->bnChainWork; - printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, - DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - - // Load bnBestInvalidWork, OK if it doesn't exist - ReadBestInvalidWork(bnBestInvalidWork); - - // Verify blocks in the best chain - int nCheckLevel = GetArg("-checklevel", 1); - int nCheckDepth = GetArg( "-checkblocks", 2500); - if (nCheckDepth == 0) - nCheckDepth = 1000000000; // suffices until the year 19000 - if (nCheckDepth > nBestHeight) - nCheckDepth = nBestHeight; - printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); - CBlockIndex* pindexFork = NULL; - map, CBlockIndex*> mapBlockPos; - for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) - { - if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) - break; - CBlock block; - if (!block.ReadFromDisk(pindex)) - return error("LoadBlockIndex() : block.ReadFromDisk failed"); - // check level 1: verify block validity - if (nCheckLevel>0 && !block.CheckBlock()) - { - printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); - pindexFork = pindex->pprev; - } - // check level 2: verify transaction index validity - if (nCheckLevel>1) - { - pair pos = make_pair(pindex->nFile, pindex->nBlockPos); - mapBlockPos[pos] = pindex; - BOOST_FOREACH(const CTransaction &tx, block.vtx) - { - uint256 hashTx = tx.GetHash(); - CTxIndex txindex; - if (ReadTxIndex(hashTx, txindex)) - { - // check level 3: checker transaction hashes - if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) - { - // either an error or a duplicate transaction - CTransaction txFound; - if (!txFound.ReadFromDisk(txindex.pos)) - { - printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); - pindexFork = pindex->pprev; - } - else - if (txFound.GetHash() != hashTx) // not a duplicate tx - { - printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); - pindexFork = pindex->pprev; - } - } - // check level 4: check whether spent txouts were spent within the main chain - unsigned int nOutput = 0; - if (nCheckLevel>3) - { - BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) - { - if (!txpos.IsNull()) - { - pair posFind = make_pair(txpos.nFile, txpos.nBlockPos); - if (!mapBlockPos.count(posFind)) - { - printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); - pindexFork = pindex->pprev; - } - // check level 6: check whether spent txouts were spent by a valid transaction that consume them - if (nCheckLevel>5) - { - CTransaction txSpend; - if (!txSpend.ReadFromDisk(txpos)) - { - printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); - pindexFork = pindex->pprev; - } - else if (!txSpend.CheckTransaction()) - { - printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); - pindexFork = pindex->pprev; - } - else - { - bool fFound = false; - BOOST_FOREACH(const CTxIn &txin, txSpend.vin) - if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) - fFound = true; - if (!fFound) - { - printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); - pindexFork = pindex->pprev; - } - } - } - } - nOutput++; - } - } - } - // check level 5: check whether all prevouts are marked spent - if (nCheckLevel>4) - { - BOOST_FOREACH(const CTxIn &txin, tx.vin) - { - CTxIndex txindex; - if (ReadTxIndex(txin.prevout.hash, txindex)) - if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull()) - { - printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str()); - pindexFork = pindex->pprev; - } - } - } - } - } - } - if (pindexFork && !fRequestShutdown) - { - // Reorg back to the fork - printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight); - CBlock block; - if (!block.ReadFromDisk(pindexFork)) - return error("LoadBlockIndex() : block.ReadFromDisk failed"); - CTxDB txdb; - block.SetBestChain(txdb, pindexFork); - } - - return true; -} - - - -bool CTxDB::LoadBlockIndexGuts() -{ - // Get database cursor - Dbc* pcursor = GetCursor(); - if (!pcursor) - return false; - - // Load mapBlockIndex - unsigned int fFlags = DB_SET_RANGE; - loop - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("blockindex"), uint256(0)); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); - fFlags = DB_NEXT; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - return false; - - // Unserialize - - try { - string strType; - ssKey >> strType; - if (strType == "blockindex" && !fRequestShutdown) - { - CDiskBlockIndex diskindex; - ssValue >> diskindex; - - // Construct block index object - CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); - pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); - pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); - pindexNew->nFile = diskindex.nFile; - pindexNew->nBlockPos = diskindex.nBlockPos; - pindexNew->nHeight = diskindex.nHeight; - pindexNew->nVersion = diskindex.nVersion; - pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; - pindexNew->nTime = diskindex.nTime; - pindexNew->nBits = diskindex.nBits; - pindexNew->nNonce = diskindex.nNonce; - - // Watch for genesis block - if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) - pindexGenesisBlock = pindexNew; - - if (!pindexNew->CheckIndex()) - return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); - } - else - { - break; // if shutdown requested or finished loading block index - } - } // try - catch (std::exception &e) { - return error("%s() : deserialize error", __PRETTY_FUNCTION__); - } - } - pcursor->close(); - - return true; -} @@ -802,6 +540,8 @@ bool CAddrDB::Read(CAddrMan& addr) // use file size to size memory buffer int fileSize = GetFilesize(filein); int dataSize = fileSize - sizeof(uint256); + //Don't try to resize to a negative number if file is small + if ( dataSize < 0 ) dataSize = 0; vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -823,20 +563,22 @@ bool CAddrDB::Read(CAddrMan& addr) if (hashIn != hashTmp) return error("CAddrman::Read() : checksum mismatch; data corrupted"); - // de-serialize address data unsigned char pchMsgTmp[4]; try { + // de-serialize file header (pchMessageStart magic number) and ssPeers >> FLATDATA(pchMsgTmp); + + // verify the network matches ours + if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp))) + return error("CAddrman::Read() : invalid network magic number"); + + // de-serialize address data into one CAddrMan object ssPeers >> addr; } catch (std::exception &e) { return error("CAddrman::Read() : I/O error or stream data corrupted"); } - // finally, verify the network matches ours - if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp))) - return error("CAddrman::Read() : invalid network magic number"); - return true; } diff --git a/src/db.h b/src/db.h index 3ceff18..ea440c4 100644 --- a/src/db.h +++ b/src/db.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_DB_H @@ -19,25 +17,23 @@ class CAddress; class CAddrMan; class CBlockLocator; class CDiskBlockIndex; -class CDiskTxPos; class CMasterKey; class COutPoint; -class CTxIndex; class CWallet; class CWalletTx; extern unsigned int nWalletDBUpdated; -void ThreadFlushWalletDB(void* parg); +void ThreadFlushWalletDB(const std::string& strWalletFile); bool BackupWallet(const CWallet& wallet, const std::string& strDest); class CDBEnv { private: - bool fDetachDB; bool fDbEnvInit; - boost::filesystem::path pathEnv; + bool fMockDb; + boost::filesystem::path path; void EnvShutdown(); @@ -49,14 +45,34 @@ public: CDBEnv(); ~CDBEnv(); - bool Open(boost::filesystem::path pathEnv_); + void MakeMock(); + bool IsMock() { return fMockDb; } + + /* + * Verify that database file strFile is OK. If it is not, + * call the callback to try to recover. + * This must be called BEFORE strFile is opened. + * Returns true if strFile is OK. + */ + enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL }; + VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, 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). + * Appends binary key/value pairs to vResult, returns true if successful. + * NOTE: reads the entire database into memory, so cannot be used + * for huge databases. + */ + typedef std::pair, std::vector > KeyValPair; + bool Salvage(std::string strFile, bool fAggressive, std::vector& vResult); + + bool Open(const boost::filesystem::path &path); void Close(); void Flush(bool fShutdown); void CheckpointLSN(std::string strFile); - void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; } - bool GetDetach() { return fDetachDB; } void CloseDb(const std::string& strFile); + bool RemoveDb(const std::string& strFile); DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC) { @@ -83,6 +99,7 @@ protected: explicit CDB(const char* pszFile, const char* pszMode="r+"); ~CDB() { Close(); } public: + void Flush(); void Close(); private: CDB(const CDB&); @@ -295,36 +312,6 @@ public: -/** Access to the transaction database (blkindex.dat) */ -class CTxDB : public CDB -{ -public: - CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { } -private: - CTxDB(const CTxDB&); - void operator=(const CTxDB&); -public: - bool ReadTxIndex(uint256 hash, CTxIndex& txindex); - bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex); - bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight); - bool EraseTxIndex(const CTransaction& tx); - bool ContainsTx(uint256 hash); - bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex); - bool ReadDiskTx(uint256 hash, CTransaction& tx); - bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex); - bool ReadDiskTx(COutPoint outpoint, CTransaction& tx); - bool WriteBlockIndex(const CDiskBlockIndex& blockindex); - bool ReadHashBestChain(uint256& hashBestChain); - bool WriteHashBestChain(uint256 hashBestChain); - bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork); - bool WriteBestInvalidWork(CBigNum bnBestInvalidWork); - bool LoadBlockIndex(); -private: - bool LoadBlockIndexGuts(); -}; - - - /** Access to the (IP) address database (peers.dat) */ class CAddrDB diff --git a/src/hash.cpp b/src/hash.cpp new file mode 100644 index 0000000..bddd8ab --- /dev/null +++ b/src/hash.cpp @@ -0,0 +1,58 @@ +#include "hash.h" + +inline uint32_t ROTL32 ( uint32_t x, int8_t r ) +{ + return (x << r) | (x >> (32 - r)); +} + +unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash) +{ + // The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + uint32_t h1 = nHashSeed; + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + const int nblocks = vDataToHash.size() / 4; + + //---------- + // body + const uint32_t * blocks = (const uint32_t *)(&vDataToHash[0] + nblocks*4); + + for(int i = -nblocks; i; i++) + { + uint32_t k1 = blocks[i]; + + k1 *= c1; + k1 = ROTL32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1,13); + h1 = h1*5+0xe6546b64; + } + + //---------- + // tail + const uint8_t * tail = (const uint8_t*)(&vDataToHash[0] + nblocks*4); + + uint32_t k1 = 0; + + switch(vDataToHash.size() & 3) + { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0]; + k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; + }; + + //---------- + // finalization + h1 ^= vDataToHash.size(); + h1 ^= h1 >> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >> 16; + + return h1; +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..536ab71 --- /dev/null +++ b/src/hash.h @@ -0,0 +1,126 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_HASH_H +#define BITCOIN_HASH_H + +#include "uint256.h" +#include "serialize.h" + +#include +#include +#include + +template +inline uint256 Hash(const T1 pbegin, const T1 pend) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +class CHashWriter +{ +private: + SHA256_CTX ctx; + +public: + int nType; + int nVersion; + + void Init() { + SHA256_Init(&ctx); + } + + CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) { + Init(); + } + + CHashWriter& write(const char *pch, size_t size) { + SHA256_Update(&ctx, pch, size); + return (*this); + } + + // invalidates the object + uint256 GetHash() { + uint256 hash1; + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; + } + + template + CHashWriter& operator<<(const T& obj) { + // Serialize to this stream + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } +}; + + +template +inline uint256 Hash(const T1 p1begin, const T1 p1end, + const T2 p2begin, const T2 p2end) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); + SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template +inline uint256 Hash(const T1 p1begin, const T1 p1end, + const T2 p2begin, const T2 p2end, + const T3 p3begin, const T3 p3end) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); + SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); + SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0])); + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template +uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) +{ + CHashWriter ss(nType, nVersion); + ss << obj; + return ss.GetHash(); +} + +template +inline uint160 Hash160(const T1 pbegin, const T1 pend) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); + uint160 hash2; + RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +inline uint160 Hash160(const std::vector& vch) +{ + return Hash160(vch.begin(), vch.end()); +} + +unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash); + +#endif diff --git a/src/init.cpp b/src/init.cpp index 36d4612..0613665 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,21 +1,22 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "db.h" + +#include "txdb.h" #include "walletdb.h" #include "bitcoinrpc.h" #include "net.h" #include "init.h" #include "util.h" #include "ui_interface.h" + #include #include #include #include #include +#include #ifndef WIN32 #include @@ -27,73 +28,112 @@ using namespace boost; CWallet* pwalletMain; CClientUIInterface uiInterface; +#ifdef WIN32 +// Win32 LevelDB doesn't use filedescriptors, and the ones used for +// accessing block files, don't count towards to fd_set size limit +// anyway. +#define MIN_CORE_FILEDESCRIPTORS 0 +#else +#define MIN_CORE_FILEDESCRIPTORS 150 +#endif + +// Used to pass flags to the Bind() function +enum BindFlags { + BF_NONE = 0, + BF_EXPLICIT = (1U << 0), + BF_REPORT_ERROR = (1U << 1) +}; + ////////////////////////////////////////////////////////////////////////////// // // Shutdown // -void ExitTimeout(void* parg) -{ -#ifdef WIN32 - Sleep(5000); - ExitProcess(0); -#endif -} +// +// Thread management and startup/shutdown: +// +// The network-processing threads are all part of a thread group +// created by AppInit() or the Qt main() function. +// +// A clean exit happens when StartShutdown() or the SIGTERM +// signal handler sets fRequestShutdown, which triggers +// the DetectShutdownThread(), which interrupts the main thread group. +// DetectShutdownThread() then exits, which causes AppInit() to +// continue (it .joins the shutdown thread). +// Shutdown() is then +// called to clean up database connections, and stop other +// 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. +// + +volatile bool fRequestShutdown = false; void StartShutdown() { -#ifdef QT_GUI - // ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards) - uiInterface.QueueShutdown(); -#else - // Without UI, Shutdown() can simply be started in a new thread - CreateThread(Shutdown, NULL); -#endif + fRequestShutdown = true; +} +bool ShutdownRequested() +{ + return fRequestShutdown; } -void Shutdown(void* parg) +static CCoinsViewDB *pcoinsdbview; + +void Shutdown() { + printf("Shutdown : In progress...\n"); static CCriticalSection cs_Shutdown; - static bool fTaken; + TRY_LOCK(cs_Shutdown, lockShutdown); + if (!lockShutdown) return; - // Make this thread recognisable as the shutdown thread RenameThread("bitcoin-shutoff"); - - bool fFirstThread = false; - { - TRY_LOCK(cs_Shutdown, lockShutdown); - if (lockShutdown) - { - fFirstThread = !fTaken; - fTaken = true; - } - } - static bool fExit; - if (fFirstThread) - { - fShutdown = true; - nTransactionsUpdated++; + nTransactionsUpdated++; + StopRPCThreads(); + ShutdownRPCMining(); + if (pwalletMain) bitdb.Flush(false); - StopNode(); - bitdb.Flush(true); - boost::filesystem::remove(GetPidFile()); - UnregisterWallet(pwalletMain); - delete pwalletMain; - CreateThread(ExitTimeout, NULL); - Sleep(50); - printf("CasinoCoin exited\n\n"); - fExit = true; -#ifndef QT_GUI - // ensure non UI client get's exited here, but let Bitcoin-Qt reach return 0; in bitcoin.cpp - exit(0); -#endif - } - else + GenerateBitcoins(false, NULL); + StopNode(); { - while (!fExit) - Sleep(500); - Sleep(100); - ExitThread(0); + LOCK(cs_main); + if (pwalletMain) + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); + if (pblocktree) + pblocktree->Flush(); + if (pcoinsTip) + pcoinsTip->Flush(); + delete pcoinsTip; pcoinsTip = NULL; + delete pcoinsdbview; pcoinsdbview = NULL; + delete pblocktree; pblocktree = NULL; + } + if (pwalletMain) + bitdb.Flush(true); + boost::filesystem::remove(GetPidFile()); + UnregisterWallet(pwalletMain); + if (pwalletMain) + delete pwalletMain; + printf("Shutdown : done\n"); +} + +// +// Signal handlers are very limited in what they are allowed to do, so: +// +void DetectShutdownThread(boost::thread_group* threadGroup) +{ + // Tell the main threads to shutdown. + while (!fRequestShutdown) + { + MilliSleep(200); + if (fRequestShutdown) + threadGroup->interrupt_all(); } } @@ -118,24 +158,27 @@ void HandleSIGHUP(int) #if !defined(QT_GUI) bool AppInit(int argc, char* argv[]) { + boost::thread_group threadGroup; + boost::thread* detectShutdownThread = NULL; + bool fRet = false; try { // // Parameters // - // If Qt is used, parameters/casinocoin.conf are parsed in qt/bitcoin.cpp's main() + // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() ParseParameters(argc, argv); if (!boost::filesystem::is_directory(GetDataDir(false))) { fprintf(stderr, "Error: Specified directory does not exist\n"); - Shutdown(NULL); + Shutdown(); } ReadConfigFile(mapArgs, mapMultiArgs); if (mapArgs.count("-?") || mapArgs.count("--help")) { - // First part of help message is specific to casinocoind / RPC client + // First part of help message is specific to bitcoind / RPC client std::string strUsage = _("CasinoCoin version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + " casinocoind [options] " + "\n" + @@ -145,7 +188,7 @@ bool AppInit(int argc, char* argv[]) strUsage += "\n" + HelpMessage(); - fprintf(stderr, "%s", strUsage.c_str()); + fprintf(stdout, "%s", strUsage.c_str()); return false; } @@ -159,16 +202,52 @@ bool AppInit(int argc, char* argv[]) int ret = CommandLineRPC(argc, argv); exit(ret); } +#if !defined(WIN32) + fDaemon = GetBoolArg("-daemon"); + if (fDaemon) + { + // Daemonize + pid_t pid = fork(); + if (pid < 0) + { + fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); + return false; + } + if (pid > 0) // Parent process, pid is child process id + { + CreatePidFile(GetPidFile(), pid); + return true; + } + // Child process falls through to rest of initialization - fRet = AppInit2(); + pid_t sid = setsid(); + if (sid < 0) + fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); + } +#endif + + detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup)); + fRet = AppInit2(threadGroup); } catch (std::exception& e) { - PrintException(&e, "AppInit()"); + PrintExceptionContinue(&e, "AppInit()"); } catch (...) { - PrintException(NULL, "AppInit()"); + PrintExceptionContinue(NULL, "AppInit()"); } - if (!fRet) - Shutdown(NULL); + if (!fRet) { + if (detectShutdownThread) + detectShutdownThread->interrupt(); + threadGroup.interrupt_all(); + } + + if (detectShutdownThread) + { + detectShutdownThread->join(); + delete detectShutdownThread; + detectShutdownThread = NULL; + } + Shutdown(); + return fRet; } @@ -177,7 +256,7 @@ int main(int argc, char* argv[]) { bool fRet = false; - // Connect casinocoind signal handlers + // Connect bitcoind signal handlers noui_connect(); fRet = AppInit(argc, argv); @@ -185,29 +264,28 @@ int main(int argc, char* argv[]) if (fRet && fDaemon) return 0; - return 1; + return (fRet ? 0 : 1); } #endif bool static InitError(const std::string &str) { - uiInterface.ThreadSafeMessageBox(str, _("CasinoCoin"), CClientUIInterface::OK | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); return false; } bool static InitWarning(const std::string &str) { - uiInterface.ThreadSafeMessageBox(str, _("CasinoCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); return true; } - -bool static Bind(const CService &addr, bool fError = true) { - if (IsLimited(addr)) +bool static Bind(const CService &addr, unsigned int flags) { + if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; std::string strError; if (!BindListenPort(addr, strError)) { - if (fError) + if (flags & BF_REPORT_ERROR) return InitError(strError); return false; } @@ -218,14 +296,13 @@ bool static Bind(const CService &addr, bool fError = true) { std::string HelpMessage() { string strUsage = _("Options:") + "\n" + + " -? " + _("This help message") + "\n" + " -conf= " + _("Specify configuration file (default: casinocoin.conf)") + "\n" + " -pid= " + _("Specify pid file (default: casinocoind.pid)") + "\n" + - " -gen " + _("Generate coins") + "\n" + - " -gen=0 " + _("Don't generate coins") + "\n" + + " -gen " + _("Generate coins (default: 0)") + "\n" + " -datadir= " + _("Specify data directory") + "\n" + " -dbcache= " + _("Set database cache size in megabytes (default: 25)") + "\n" + - " -dblogsize= " + _("Set database disk log size in megabytes (default: 100)") + "\n" + - " -timeout= " + _("Specify connection timeout (in milliseconds)") + "\n" + + " -timeout= " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n" + " -proxy= " + _("Connect through socks proxy") + "\n" + " -socks= " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" + " -tor= " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n" @@ -238,14 +315,15 @@ std::string HelpMessage() " -externalip= " + _("Specify your own public address") + "\n" + " -onlynet= " + _("Only connect to nodes in network (IPv4, IPv6 or Tor)") + "\n" + " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" + - " -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" + + " -checkpoints " + _("Only accept block chain matching built-in checkpoints (default: 1)") + "\n" + " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" + - " -bind= " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" + + " -bind= " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n" + " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" + " -banscore= " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -bantime= " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + " -maxreceivebuffer= " + _("Maximum per-connection receive buffer, *1000 bytes (default: 5000)") + "\n" + " -maxsendbuffer= " + _("Maximum per-connection send buffer, *1000 bytes (default: 1000)") + "\n" + + " -bloomfilters " + _("Allow peers to set bloom filters (default: 1)") + "\n" + #ifdef USE_UPNP #if USE_UPNP " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n" + @@ -253,7 +331,6 @@ std::string HelpMessage() " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n" + #endif #endif - " -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" + " -paytxfee= " + _("Fee per KB to add to transactions you send") + "\n" + " -mininput= " + _("When creating transactions, ignore inputs with value less than this (default: 0.0001)") + "\n" + #ifdef QT_GUI @@ -265,27 +342,40 @@ std::string HelpMessage() " -testnet " + _("Use the test network") + "\n" + " -debug " + _("Output extra debugging information. Implies all other -debug* options") + "\n" + " -debugnet " + _("Output extra network debugging information") + "\n" + - " -logtimestamps " + _("Prepend debug output with timestamp") + "\n" + + " -logtimestamps " + _("Prepend debug output with timestamp (default: 1)") + "\n" + + " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n" + " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n" + #ifdef WIN32 " -printtodebugger " + _("Send trace/debug info to debugger") + "\n" + #endif " -rpcuser= " + _("Username for JSON-RPC connections") + "\n" + " -rpcpassword= " + _("Password for JSON-RPC connections") + "\n" + - " -rpcport= " + _("Listen for JSON-RPC connections on (default: 47970)") + "\n" + + " -rpcport= " + _("Listen for JSON-RPC connections on (default: 47970 or testnet: 17970)") + "\n" + " -rpcallowip= " + _("Allow JSON-RPC connections from specified IP address") + "\n" + +#ifndef QT_GUI " -rpcconnect= " + _("Send commands to node running on (default: 127.0.0.1)") + "\n" + +#endif + " -rpcthreads= " + _("Set the number of threads to service RPC calls (default: 4)") + "\n" + " -blocknotify= " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" + + " -walletnotify= " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" + + " -alertnotify= " + _("Execute command when a relevant alert is received (%s in cmd is replaced by message)") + "\n" + " -upgradewallet " + _("Upgrade wallet to latest format") + "\n" + " -keypool= " + _("Set key pool size to (default: 100)") + "\n" + " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" + - " -checkblocks= " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + - " -checklevel= " + _("How thorough the block verification is (0-6, default: 1)") + "\n" + - " -loadblock= " + _("Imports blocks from external blk000?.dat file") + "\n" + - " -? " + _("This help message") + "\n"; + " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" + + " -checkblocks= " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n" + + " -checklevel= " + _("How thorough the block verification is (0-4, default: 3)") + "\n" + + " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n" + + " -loadblock= " + _("Imports blocks from external blk000??.dat file") + "\n" + + " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + "\n" + + " -par= " + _("Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)") + "\n" + - strUsage += string() + - _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" + + "\n" + _("Block creation options:") + "\n" + + " -blockminsize= " + _("Set minimum block size in bytes (default: 0)") + "\n" + + " -blockmaxsize= " + _("Set maximum block size in bytes (default: 250000)") + "\n" + + " -blockprioritysize= " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n" + + + "\n" + _("SSL options: (see the CasinoCoin Wiki for SSL setup instructions)") + "\n" + " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" + " -rpcsslcertificatechainfile= " + _("Server certificate file (default: server.cert)") + "\n" + " -rpcsslprivatekeyfile= " + _("Server private key (default: server.pem)") + "\n" + @@ -294,25 +384,106 @@ std::string HelpMessage() return strUsage; } -/** Initialize casinocoin. +struct CImportingNow +{ + CImportingNow() { + assert(fImporting == false); + fImporting = true; + } + + ~CImportingNow() { + assert(fImporting == true); + fImporting = false; + } +}; + +void ThreadImport(std::vector vImportFiles) +{ + RenameThread("bitcoin-loadblk"); + + // -reindex + if (fReindex) { + CImportingNow imp; + int nFile = 0; + while (true) { + CDiskBlockPos pos(nFile, 0); + FILE *file = OpenBlockFile(pos, true); + if (!file) + break; + printf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); + LoadExternalBlockFile(file, &pos); + nFile++; + } + pblocktree->WriteReindexing(false); + fReindex = false; + printf("Reindexing finished\n"); + // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): + InitBlockIndex(); + } + + // hardcoded $DATADIR/bootstrap.dat + filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; + if (filesystem::exists(pathBootstrap)) { + FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); + if (file) { + CImportingNow imp; + filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; + printf("Importing bootstrap.dat...\n"); + LoadExternalBlockFile(file); + RenameOver(pathBootstrap, pathBootstrapOld); + } + } + + // -loadblock= + BOOST_FOREACH(boost::filesystem::path &path, vImportFiles) { + FILE *file = fopen(path.string().c_str(), "rb"); + if (file) { + CImportingNow imp; + printf("Importing %s...\n", path.string().c_str()); + LoadExternalBlockFile(file); + } + } +} + +/** Initialize bitcoin. * @pre Parameters should be parsed and config file should be read. */ -bool AppInit2() +bool AppInit2(boost::thread_group& threadGroup) { // ********************************************************* Step 1: setup #ifdef _MSC_VER - // Turn off microsoft heap dump noise + // Turn off Microsoft heap dump noise _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); #endif #if _MSC_VER >= 1400 - // Disable confusing "helpful" text message on abort, ctrl-c + // Disable confusing "helpful" text message on abort, Ctrl-C _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); #endif +#ifdef WIN32 + // Enable Data Execution Prevention (DEP) + // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008 + // A failure is non-critical and needs no further attention! +#ifndef PROCESS_DEP_ENABLE +// We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), +// which is not correct. Can be removed, when GCCs winbase.h is fixed! +#define PROCESS_DEP_ENABLE 0x00000001 +#endif + typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); + PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); + if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE); + + // Initialize Windows Sockets + WSADATA wsadata; + int ret = WSAStartup(MAKEWORD(2,2), &wsadata); + if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2) + { + return InitError(strprintf("Error: Winsock library failed to start (WSAStartup returned error %d)", ret)); + } +#endif #ifndef WIN32 umask(077); -#endif -#ifndef WIN32 + // Clean shutdown on SIGTERM struct sigaction sa; sa.sa_handler = HandleSIGTERM; @@ -332,8 +503,9 @@ bool AppInit2() // ********************************************************* Step 2: parameter interactions fTestNet = GetBoolArg("-testnet"); - - SoftSetBoolArg("-irc", false); + fBloomFilters = GetBoolArg("-bloomfilters", true); + if (fBloomFilters) + nLocalServices |= NODE_BLOOM; if (mapArgs.count("-bind")) { // when specifying an explicit binding address, you want to listen on it @@ -341,7 +513,7 @@ bool AppInit2() SoftSetBoolArg("-listen", true); } - if (mapArgs.count("-connect")) { + if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { // when only connecting to trusted nodes, do not seed via DNS, or listen by default SoftSetBoolArg("-dnsseed", false); SoftSetBoolArg("-listen", false); @@ -363,9 +535,34 @@ bool AppInit2() SoftSetBoolArg("-discover", false); } + if (GetBoolArg("-salvagewallet")) { + // Rewrite just private keys: rescan to find transactions + SoftSetBoolArg("-rescan", true); + } + + // Make sure enough file descriptors are available + int nBind = std::max((int)mapArgs.count("-bind"), 1); + nMaxConnections = GetArg("-maxconnections", 125); + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); + int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + if (nFD < MIN_CORE_FILEDESCRIPTORS) + return InitError(_("Not enough file descriptors available.")); + if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) + nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS; + // ********************************************************* Step 3: parameter-to-internal-flags fDebug = GetBoolArg("-debug"); + fBenchmark = GetBoolArg("-benchmark"); + + // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency + nScriptCheckThreads = GetArg("-par", 0); + if (nScriptCheckThreads <= 0) + nScriptCheckThreads += boost::thread::hardware_concurrency(); + if (nScriptCheckThreads <= 1) + nScriptCheckThreads = 0; + else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) + nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; // -debug implies fDebug* if (fDebug) @@ -373,14 +570,6 @@ bool AppInit2() else fDebugNet = GetBoolArg("-debugnet"); - bitdb.SetDetach(GetBoolArg("-detachdb", false)); - -#if !defined(WIN32) && !defined(QT_GUI) - fDaemon = GetBoolArg("-daemon"); -#else - fDaemon = false; -#endif - if (fDaemon) fServer = true; else @@ -392,7 +581,8 @@ bool AppInit2() #endif fPrintToConsole = GetBoolArg("-printtoconsole"); fPrintToDebugger = GetBoolArg("-printtodebugger"); - fLogTimestamps = GetBoolArg("-logtimestamps"); + fLogTimestamps = GetBoolArg("-logtimestamps", true); + bool fDisableWallet = GetBoolArg("-disablewallet", false); if (mapArgs.count("-timeout")) { @@ -407,13 +597,35 @@ bool AppInit2() const char* pszP2SH = "/P2SH/"; COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); + // Fee-per-kilobyte amount considered the same as "free" + // If you are mining, be careful setting this: + // if you set it to zero then + // a transaction spammer can cheaply fill blocks using + // 1-satoshi-fee transactions. It should be set above the real + // cost to you of processing a transaction. + if (mapArgs.count("-mintxfee")) + { + int64 n = 0; + if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) + CTransaction::nMinTxFee = n; + else + return InitError(strprintf(_("Invalid amount for -mintxfee=: '%s'"), mapArgs["-mintxfee"].c_str())); + } + if (mapArgs.count("-minrelaytxfee")) + { + int64 n = 0; + if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) + CTransaction::nMinRelayTxFee = n; + else + return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%s'"), mapArgs["-minrelaytxfee"].c_str())); + } if (mapArgs.count("-paytxfee")) { if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s'"), mapArgs["-paytxfee"].c_str())); if (nTransactionFee > 0.25 * COIN) - InitWarning(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction.")); + InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); } if (mapArgs.count("-mininput")) @@ -424,54 +636,94 @@ bool AppInit2() // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log - // Make sure only a single CasinoCoin process is using the data directory. + 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. if (file) fclose(file); static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); if (!lock.try_lock()) - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. CasinoCoin is probably already running."), GetDataDir().string().c_str())); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. CasinoCoin is probably already running."), strDataDir.c_str())); -#if !defined(WIN32) && !defined(QT_GUI) - if (fDaemon) - { - // Daemonize - pid_t pid = fork(); - if (pid < 0) - { - fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); - return false; - } - if (pid > 0) - { - CreatePidFile(GetPidFile(), pid); - return true; - } - - pid_t sid = setsid(); - if (sid < 0) - fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); - } -#endif - - if (!fDebug) + if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf("CasinoCoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); - printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); + printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); + if (!fLogTimestamps) + printf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); - printf("Used data directory %s\n", GetDataDir().string().c_str()); + printf("Using data directory %s\n", strDataDir.c_str()); + printf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); std::ostringstream strErrors; if (fDaemon) fprintf(stdout, "CasinoCoin server starting\n"); + if (nScriptCheckThreads) { + printf("Using %u threads for script verification\n", nScriptCheckThreads); + for (int i=0; i %s\n", source.string().c_str(), dest.string().c_str()); + linked = true; + } catch (filesystem::filesystem_error & e) { + // Note: hardlink creation failing is not a disaster, it just means + // blocks will get re-downloaded from peers. + printf("Error hardlinking blk%04u.dat : %s\n", i, e.what()); + break; + } + } + if (linked) + { + fReindex = true; + } } - uiInterface.InitMessage(_("Loading block index...")); - printf("Loading block index...\n"); - nStart = GetTimeMillis(); - if (!LoadBlockIndex()) - strErrors << _("Error loading blkindex.dat") << "\n"; + // cache size calculations + size_t nTotalCache = GetArg("-dbcache", 25) << 20; + if (nTotalCache < (1 << 22)) + nTotalCache = (1 << 22); // total cache cannot be less than 4 MiB + size_t nBlockTreeDBCache = nTotalCache / 8; + if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) + nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB + nTotalCache -= nBlockTreeDBCache; + size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache + nTotalCache -= nCoinDBCache; + nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes + + bool fLoaded = false; + while (!fLoaded) { + bool fReset = fReindex; + std::string strLoadError; + + uiInterface.InitMessage(_("Loading block index...")); + + nStart = GetTimeMillis(); + do { + try { + UnloadBlockIndex(); + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; + + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); + pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + + if (fReindex) + pblocktree->WriteReindexing(true); + + if (!LoadBlockIndex()) { + strLoadError = _("Error loading block database"); + break; + } + + // If the loaded chain has a wrong genesis, bail out immediately + // (we're likely using a testnet datadir, or the other way around). + if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL) + return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); + + // Initialize the block index (no-op if non-empty database was already loaded) + if (!InitBlockIndex()) { + strLoadError = _("Error initializing block database"); + break; + } + + // Check for changed -txindex state + if (fTxIndex != GetBoolArg("-txindex", false)) { + strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); + break; + } + + uiInterface.InitMessage(_("Verifying blocks...")); + if (!VerifyDB(GetArg("-checklevel", 3), + GetArg( "-checkblocks", 288))) { + strLoadError = _("Corrupted block database detected"); + break; + } + } catch(std::exception &e) { + strLoadError = _("Error opening block database"); + break; + } + + fLoaded = true; + } while(false); + + if (!fLoaded) { + // first suggest a reindex + if (!fReset) { + bool fRet = uiInterface.ThreadSafeMessageBox( + strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?"), + "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); + if (fRet) { + fReindex = true; + fRequestShutdown = false; + } else { + return false; + } + } else { + return InitError(strLoadError); + } + } + } // as LoadBlockIndex can take several minutes, it's possible the user - // requested to kill casinocoin-qt during the last operation. If so, exit. + // requested to kill bitcoin-qt during the last operation. If so, exit. // As the program has not fully started yet, Shutdown() is possibly overkill. if (fRequestShutdown) { @@ -623,103 +977,119 @@ bool AppInit2() return false; } - // ********************************************************* Step 7: load wallet + // ********************************************************* Step 8: load wallet - uiInterface.InitMessage(_("Loading wallet...")); - printf("Loading wallet...\n"); - nStart = GetTimeMillis(); - bool fFirstRun; - pwalletMain = new CWallet("wallet.dat"); - int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); - if (nLoadWalletRet != DB_LOAD_OK) - { - if (nLoadWalletRet == DB_CORRUPT) - strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; - else if (nLoadWalletRet == DB_TOO_NEW) - strErrors << _("Error loading wallet.dat: Wallet requires newer version of CasinoCoin") << "\n"; - else if (nLoadWalletRet == DB_NEED_REWRITE) - { - strErrors << _("Wallet needed to be rewritten: restart CasinoCoin to complete") << "\n"; - printf("%s", strErrors.str().c_str()); - return InitError(strErrors.str()); - } - else - strErrors << _("Error loading wallet.dat") << "\n"; - } + if (fDisableWallet) { + printf("Wallet disabled!\n"); + pwalletMain = NULL; + } else { + uiInterface.InitMessage(_("Loading wallet...")); - if (GetBoolArg("-upgradewallet", fFirstRun)) - { - int nMaxVersion = GetArg("-upgradewallet", 0); - if (nMaxVersion == 0) // the -upgradewallet without argument case - { - printf("Performing wallet upgrade to %i\n", FEATURE_LATEST); - nMaxVersion = CLIENT_VERSION; - pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately - } - else - printf("Allowing wallet upgrade up to %i\n", nMaxVersion); - if (nMaxVersion < pwalletMain->GetVersion()) - { - printf("Max version: %i\n", nMaxVersion); - printf("Wallet version: %i\n", pwalletMain->GetVersion()); - strErrors << _("Cannot downgrade wallet") << "\n"; - } - pwalletMain->SetMaxVersion(nMaxVersion); - } - - if (fFirstRun) - { - // Create new keyUser and set as default key - RandAddSeedPerfmon(); - - CPubKey newDefaultKey; - if (!pwalletMain->GetKeyFromPool(newDefaultKey, false)) - strErrors << _("Cannot initialize keypool") << "\n"; - pwalletMain->SetDefaultKey(newDefaultKey); - if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) - strErrors << _("Cannot write default address") << "\n"; - } - - printf("%s", strErrors.str().c_str()); - printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); - - RegisterWallet(pwalletMain); - - CBlockIndex *pindexRescan = pindexBest; - if (GetBoolArg("-rescan")) - pindexRescan = pindexGenesisBlock; - else - { - CWalletDB walletdb("wallet.dat"); - CBlockLocator locator; - if (walletdb.ReadBestBlock(locator)) - pindexRescan = locator.GetBlockIndex(); - } - if (pindexBest != pindexRescan) - { - uiInterface.InitMessage(_("Rescanning...")); - printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); - pwalletMain->ScanForWalletTransactions(pindexRescan, true); - printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); - } + bool fFirstRun = true; + pwalletMain = new CWallet("wallet.dat"); + DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); + if (nLoadWalletRet != DB_LOAD_OK) + { + if (nLoadWalletRet == DB_CORRUPT) + strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; + else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) + { + string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect.")); + InitWarning(msg); + } + else if (nLoadWalletRet == DB_TOO_NEW) + strErrors << _("Error loading wallet.dat: Wallet requires newer version of CasinoCoin") << "\n"; + else if (nLoadWalletRet == DB_NEED_REWRITE) + { + strErrors << _("Wallet needed to be rewritten: restart CasinoCoin to complete") << "\n"; + printf("%s", strErrors.str().c_str()); + return InitError(strErrors.str()); + } + else + strErrors << _("Error loading wallet.dat") << "\n"; + } - // ********************************************************* Step 8: import blocks + if (GetBoolArg("-upgradewallet", fFirstRun)) + { + int nMaxVersion = GetArg("-upgradewallet", 0); + if (nMaxVersion == 0) // the -upgradewallet without argument case + { + printf("Performing wallet upgrade to %i\n", FEATURE_LATEST); + nMaxVersion = CLIENT_VERSION; + pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + } + else + printf("Allowing wallet upgrade up to %i\n", nMaxVersion); + if (nMaxVersion < pwalletMain->GetVersion()) + strErrors << _("Cannot downgrade wallet") << "\n"; + pwalletMain->SetMaxVersion(nMaxVersion); + } + if (fFirstRun) + { + // Create new keyUser and set as default key + RandAddSeedPerfmon(); + + CPubKey newDefaultKey; + if (pwalletMain->GetKeyFromPool(newDefaultKey, false)) { + pwalletMain->SetDefaultKey(newDefaultKey); + if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) + strErrors << _("Cannot write default address") << "\n"; + } + + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); + } + + printf("%s", strErrors.str().c_str()); + printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); + + RegisterWallet(pwalletMain); + + CBlockIndex *pindexRescan = pindexBest; + if (GetBoolArg("-rescan")) + pindexRescan = pindexGenesisBlock; + else + { + CWalletDB walletdb("wallet.dat"); + CBlockLocator locator; + if (walletdb.ReadBestBlock(locator)) + pindexRescan = locator.GetBlockIndex(); + else + pindexRescan = pindexGenesisBlock; + } + if (pindexBest && pindexBest != pindexRescan) + { + uiInterface.InitMessage(_("Rescanning...")); + printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); + nStart = GetTimeMillis(); + pwalletMain->ScanForWalletTransactions(pindexRescan, true); + printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); + nWalletDBUpdated++; + } + } // (!fDisableWallet) + + // ********************************************************* Step 9: import blocks + + // scan for better chains in the block chain database, that are not yet connected in the active best chain + CValidationState state; + if (!ConnectBestBlock(state)) + strErrors << "Failed to connect best block"; + + std::vector vImportFiles; if (mapArgs.count("-loadblock")) { BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"]) - { - FILE *file = fopen(strFile.c_str(), "rb"); - if (file) - LoadExternalBlockFile(file); - } + vImportFiles.push_back(strFile); } + threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - // ********************************************************* Step 9: load peers + // ********************************************************* Step 10: load peers uiInterface.InitMessage(_("Loading addresses...")); - printf("Loading addresses...\n"); + nStart = GetTimeMillis(); { @@ -731,44 +1101,45 @@ bool AppInit2() printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n", addrman.size(), GetTimeMillis() - nStart); - // ********************************************************* Step 10: start node + // ********************************************************* Step 11: start node if (!CheckDiskSpace()) return false; - RandAddSeedPerfmon(); - - //// debug print - printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); - printf("nBestHeight = %d\n", nBestHeight); - printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size()); - printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size()); - printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size()); - - if (!CreateThread(StartNode, NULL)) - InitError(_("Error: could not start node")); - - if (fServer) - CreateThread(ThreadRPCServer, NULL); - - // ********************************************************* Step 11: finished - - uiInterface.InitMessage(_("Done loading")); - printf("Done loading\n"); - if (!strErrors.str().empty()) return InitError(strErrors.str()); - // Add wallet transactions that aren't already in a block to mapTransactions - pwalletMain->ReacceptWalletTransactions(); + RandAddSeedPerfmon(); -#if !defined(QT_GUI) - // Loop until process is exit()ed from shutdown() function, - // called from ThreadRPCServer thread when a "stop" command is received. - while (1) - Sleep(5000); -#endif + //// debug print + printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size()); + printf("nBestHeight = %d\n", nBestHeight); + printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); + printf("mapWallet.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); + printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); - return true; + StartNode(threadGroup); + + // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly. + InitRPCMining(); + if (fServer) + StartRPCThreads(); + + // Generate coins in the background + if (pwalletMain) + GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain); + + // ********************************************************* Step 12: finished + + uiInterface.InitMessage(_("Done loading")); + + 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))); + } + + return !fRequestShutdown; } - diff --git a/src/init.h b/src/init.h index 89230f1..5927670 100644 --- a/src/init.h +++ b/src/init.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_INIT_H @@ -12,8 +10,9 @@ extern CWallet* pwalletMain; void StartShutdown(); -void Shutdown(void* parg); -bool AppInit2(); +bool ShutdownRequested(); +void Shutdown(); +bool AppInit2(boost::thread_group& threadGroup); std::string HelpMessage(); #endif diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h index 28c49dd..6b4978a 100644 --- a/src/json/json_spirit_writer_template.h +++ b/src/json/json_spirit_writer_template.h @@ -28,7 +28,8 @@ namespace json_spirit template< class String_type > String_type non_printable_to_string( unsigned int c ) { - typedef typename String_type::value_type Char_type; + // Silence the warning: typedef ‘Char_type’ locally defined but not used [-Wunused-local-typedefs] + // typedef typename String_type::value_type Char_type; String_type result( 6, '\\' ); diff --git a/src/key.cpp b/src/key.cpp index 6a5dcf0..1ab4c62 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,16 +1,17 @@ // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include - #include +#include #include #include "key.h" + +// anonymous namespace with local implementation code (OpenSSL interaction) +namespace { + // Generate a private key from just the secret parameter int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) { @@ -50,7 +51,7 @@ err: // Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields // recid selects which key is recovered -// if check is nonzero, additional checks are performed +// if check is non-zero, additional checks are performed int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) { if (!eckey) return 0; @@ -122,266 +123,274 @@ err: return ret; } -void CKey::SetCompressedPubKey() -{ - EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); - fCompressedPubKey = true; -} +// RAII Wrapper around OpenSSL's EC_KEY +class CECKey { +private: + EC_KEY *pkey; -void CKey::Reset() -{ - fCompressedPubKey = false; - if (pkey != NULL) +public: + CECKey() { + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + assert(pkey != NULL); + } + + ~CECKey() { EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); - fSet = false; -} - -CKey::CKey() -{ - pkey = NULL; - Reset(); -} - -CKey::CKey(const CKey& b) -{ - pkey = EC_KEY_dup(b.pkey); - if (pkey == NULL) - throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); - fSet = b.fSet; -} - -CKey& CKey::operator=(const CKey& b) -{ - if (!EC_KEY_copy(pkey, b.pkey)) - throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); - fSet = b.fSet; - return (*this); -} - -CKey::~CKey() -{ - EC_KEY_free(pkey); -} - -bool CKey::IsNull() const -{ - return !fSet; -} - -bool CKey::IsCompressed() const -{ - return fCompressedPubKey; -} - -void CKey::MakeNewKey(bool fCompressed) -{ - if (!EC_KEY_generate_key(pkey)) - throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); - if (fCompressed) - SetCompressedPubKey(); - fSet = true; -} - -bool CKey::SetPrivKey(const CPrivKey& vchPrivKey) -{ - const unsigned char* pbegin = &vchPrivKey[0]; - if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) - return false; - fSet = true; - return true; -} - -bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) -{ - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); - if (vchSecret.size() != 32) - throw key_error("CKey::SetSecret() : secret must be 32 bytes"); - BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); - if (bn == NULL) - throw key_error("CKey::SetSecret() : BN_bin2bn failed"); - if (!EC_KEY_regenerate_key(pkey,bn)) - { - BN_clear_free(bn); - throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); } - BN_clear_free(bn); - fSet = true; - if (fCompressed || fCompressedPubKey) - SetCompressedPubKey(); - return true; -} -CSecret CKey::GetSecret(bool &fCompressed) const -{ - CSecret vchRet; - vchRet.resize(32); - const BIGNUM *bn = EC_KEY_get0_private_key(pkey); - int nBytes = BN_num_bytes(bn); - if (bn == NULL) - throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); - int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); - if (n != nBytes) - throw key_error("CKey::GetSecret(): BN_bn2bin failed"); - fCompressed = fCompressedPubKey; - return vchRet; -} - -CPrivKey CKey::GetPrivKey() const -{ - int nSize = i2d_ECPrivateKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); - CPrivKey vchPrivKey(nSize, 0); - unsigned char* pbegin = &vchPrivKey[0]; - if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); - return vchPrivKey; -} - -bool CKey::SetPubKey(const CPubKey& vchPubKey) -{ - const unsigned char* pbegin = &vchPubKey.vchPubKey[0]; - if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size())) - return false; - fSet = true; - if (vchPubKey.vchPubKey.size() == 33) - SetCompressedPubKey(); - return true; -} - -CPubKey CKey::GetPubKey() const -{ - int nSize = i2o_ECPublicKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); - std::vector vchPubKey(nSize, 0); - unsigned char* pbegin = &vchPubKey[0]; - if (i2o_ECPublicKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); - return CPubKey(vchPubKey); -} - -bool CKey::Sign(uint256 hash, std::vector& vchSig) -{ - unsigned int nSize = ECDSA_size(pkey); - vchSig.resize(nSize); // Make sure it is big enough - if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) - { - vchSig.clear(); - return false; + void GetSecretBytes(unsigned char vch[32]) const { + const BIGNUM *bn = EC_KEY_get0_private_key(pkey); + assert(bn); + int nBytes = BN_num_bytes(bn); + int n=BN_bn2bin(bn,&vch[32 - nBytes]); + assert(n == nBytes); + memset(vch, 0, 32 - nBytes); } - vchSig.resize(nSize); // Shrink to fit actual size - return true; -} -// create a compact signature (65 bytes), which allows reconstructing the used public key -// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. -// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, -// 0x1D = second key with even y, 0x1E = second key with odd y -bool CKey::SignCompact(uint256 hash, std::vector& vchSig) -{ - bool fOk = false; - ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); - if (sig==NULL) - return false; - vchSig.clear(); - vchSig.resize(65,0); - int nBitsR = BN_num_bits(sig->r); - int nBitsS = BN_num_bits(sig->s); - if (nBitsR <= 256 && nBitsS <= 256) - { - int nRecId = -1; - for (int i=0; i<4; i++) - { - CKey keyRec; - keyRec.fSet = true; - if (fCompressedPubKey) - keyRec.SetCompressedPubKey(); - if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) - if (keyRec.GetPubKey() == this->GetPubKey()) - { - nRecId = i; - break; - } + void SetSecretBytes(const unsigned char vch[32]) { + BIGNUM bn; + BN_init(&bn); + assert(BN_bin2bn(vch, 32, &bn)); + assert(EC_KEY_regenerate_key(pkey, &bn)); + BN_clear_free(&bn); + } + + void GetPrivKey(CPrivKey &privkey, bool fCompressed) { + EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); + int nSize = i2d_ECPrivateKey(pkey, NULL); + assert(nSize); + privkey.resize(nSize); + unsigned char* pbegin = &privkey[0]; + int nSize2 = i2d_ECPrivateKey(pkey, &pbegin); + assert(nSize == nSize2); + } + + bool SetPrivKey(const CPrivKey &privkey) { + const unsigned char* pbegin = &privkey[0]; + if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) { + // d2i_ECPrivateKey returns true if parsing succeeds. + // This doesn't necessarily mean the key is valid. + if (EC_KEY_check_key(pkey)) + return true; } - - if (nRecId == -1) - throw key_error("CKey::SignCompact() : unable to construct recoverable key"); - - vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); - BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); - BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); - fOk = true; - } - ECDSA_SIG_free(sig); - return fOk; -} - -// reconstruct public key from a compact signature -// This is only slightly more CPU intensive than just verifying it. -// If this function succeeds, the recovered public key is guaranteed to be valid -// (the signature is a valid signature of the given data for that key) -bool CKey::SetCompactSignature(uint256 hash, const std::vector& vchSig) -{ - if (vchSig.size() != 65) return false; - int nV = vchSig[0]; - if (nV<27 || nV>=35) - return false; - ECDSA_SIG *sig = ECDSA_SIG_new(); - BN_bin2bn(&vchSig[1],32,sig->r); - BN_bin2bn(&vchSig[33],32,sig->s); - - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (nV >= 31) - { - SetCompressedPubKey(); - nV -= 4; } - if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) - { - fSet = true; - ECDSA_SIG_free(sig); + + void GetPubKey(CPubKey &pubkey, bool fCompressed) { + EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); + int nSize = i2o_ECPublicKey(pkey, NULL); + assert(nSize); + assert(nSize <= 65); + unsigned char c[65]; + unsigned char *pbegin = c; + int nSize2 = i2o_ECPublicKey(pkey, &pbegin); + assert(nSize == nSize2); + pubkey.Set(&c[0], &c[nSize]); + } + + bool SetPubKey(const CPubKey &pubkey) { + const unsigned char* pbegin = pubkey.begin(); + return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size()); + } + + bool Sign(const uint256 &hash, std::vector& vchSig) { + unsigned int nSize = ECDSA_size(pkey); + vchSig.resize(nSize); // Make sure it is big enough + assert(ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)); + vchSig.resize(nSize); // Shrink to fit actual size return true; } - return false; -} -bool CKey::Verify(uint256 hash, const std::vector& vchSig) -{ - // -1 = error, 0 = bad sig, 1 = good - if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + bool Verify(const uint256 &hash, const std::vector& vchSig) { + // -1 = error, 0 = bad sig, 1 = good + if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + return false; + return true; + } + + bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec) { + bool fOk = false; + ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); + if (sig==NULL) + return false; + memset(p64, 0, 64); + int nBitsR = BN_num_bits(sig->r); + int nBitsS = BN_num_bits(sig->s); + if (nBitsR <= 256 && nBitsS <= 256) { + CPubKey pubkey; + GetPubKey(pubkey, true); + for (int i=0; i<4; i++) { + CECKey keyRec; + if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) { + CPubKey pubkeyRec; + keyRec.GetPubKey(pubkeyRec, true); + if (pubkeyRec == pubkey) { + rec = i; + fOk = true; + break; + } + } + } + assert(fOk); + BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]); + BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]); + } + ECDSA_SIG_free(sig); + return fOk; + } + + // reconstruct public key from a compact signature + // This is only slightly more CPU intensive than just verifying it. + // If this function succeeds, the recovered public key is guaranteed to be valid + // (the signature is a valid signature of the given data for that key) + bool Recover(const uint256 &hash, const unsigned char *p64, int rec) + { + if (rec<0 || rec>=3) + return false; + ECDSA_SIG *sig = ECDSA_SIG_new(); + BN_bin2bn(&p64[0], 32, sig->r); + BN_bin2bn(&p64[32], 32, sig->s); + bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1; + ECDSA_SIG_free(sig); + return ret; + } +}; + +}; // end of anonymous namespace + +bool CKey::Check(const unsigned char *vch) { + // Do not convert to OpenSSL's data structures for range-checking keys, + // it's easy enough to do directly. + static const unsigned char vchMax[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 + }; + bool fIsZero = true; + for (int i=0; i<32 && fIsZero; i++) + if (vch[i] != 0) + fIsZero = false; + if (fIsZero) return false; - + for (int i=0; i<32; i++) { + if (vch[i] < vchMax[i]) + return true; + if (vch[i] > vchMax[i]) + return false; + } return true; } -bool CKey::VerifyCompact(uint256 hash, const std::vector& vchSig) -{ - CKey key; - if (!key.SetCompactSignature(hash, vchSig)) - return false; - if (GetPubKey() != key.GetPubKey()) - return false; +void CKey::MakeNewKey(bool fCompressedIn) { + do { + RAND_bytes(vch, sizeof(vch)); + } while (!Check(vch)); + fValid = true; + fCompressed = fCompressedIn; +} +bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { + CECKey key; + if (!key.SetPrivKey(privkey)) + return false; + key.GetSecretBytes(vch); + fCompressed = fCompressedIn; + fValid = true; return true; } -bool CKey::IsValid() -{ - if (!fSet) - return false; - - bool fCompr; - CSecret secret = GetSecret(fCompr); - CKey key2; - key2.SetSecret(secret, fCompr); - return GetPubKey() == key2.GetPubKey(); +CPrivKey CKey::GetPrivKey() const { + assert(fValid); + CECKey key; + key.SetSecretBytes(vch); + CPrivKey privkey; + key.GetPrivKey(privkey, fCompressed); + return privkey; +} + +CPubKey CKey::GetPubKey() const { + assert(fValid); + CECKey key; + key.SetSecretBytes(vch); + CPubKey pubkey; + key.GetPubKey(pubkey, fCompressed); + return pubkey; +} + +bool CKey::Sign(const uint256 &hash, std::vector& vchSig) const { + if (!fValid) + return false; + CECKey key; + key.SetSecretBytes(vch); + return key.Sign(hash, vchSig); +} + +bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) const { + if (!fValid) + return false; + CECKey key; + key.SetSecretBytes(vch); + vchSig.resize(65); + int rec = -1; + if (!key.SignCompact(hash, &vchSig[1], rec)) + return false; + assert(rec != -1); + vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); + return true; +} + +bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { + if (!IsValid()) + return false; + CECKey key; + if (!key.SetPubKey(*this)) + return false; + if (!key.Verify(hash, vchSig)) + return false; + return true; +} + +bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector& vchSig) { + if (vchSig.size() != 65) + return false; + CECKey key; + if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4)) + return false; + key.GetPubKey(*this, (vchSig[0] - 27) & 4); + return true; +} + +bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector& vchSig) const { + if (!IsValid()) + return false; + if (vchSig.size() != 65) + return false; + CECKey key; + if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4)) + return false; + CPubKey pubkeyRec; + key.GetPubKey(pubkeyRec, IsCompressed()); + if (*this != pubkeyRec) + return false; + return true; +} + +bool CPubKey::IsFullyValid() const { + if (!IsValid()) + return false; + CECKey key; + if (!key.SetPubKey(*this)) + return false; + return true; +} + +bool CPubKey::Decompress() { + if (!IsValid()) + return false; + CECKey key; + if (!key.SetPubKey(*this)) + return false; + key.GetPubKey(*this, false); + return true; } diff --git a/src/key.h b/src/key.h index 9d02707..ce469ad 100644 --- a/src/key.h +++ b/src/key.h @@ -1,37 +1,17 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers +// Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KEY_H #define BITCOIN_KEY_H -#include #include #include "allocators.h" #include "serialize.h" #include "uint256.h" -#include "util.h" +#include "hash.h" -#include // for EC_KEY definition - -// secp160k1 -// const unsigned int PRIVATE_KEY_SIZE = 192; -// const unsigned int PUBLIC_KEY_SIZE = 41; -// const unsigned int SIGNATURE_SIZE = 48; -// -// secp192k1 -// const unsigned int PRIVATE_KEY_SIZE = 222; -// const unsigned int PUBLIC_KEY_SIZE = 49; -// const unsigned int SIGNATURE_SIZE = 57; -// -// secp224k1 -// const unsigned int PRIVATE_KEY_SIZE = 250; -// const unsigned int PUBLIC_KEY_SIZE = 57; -// const unsigned int SIGNATURE_SIZE = 66; -// // secp256k1: // const unsigned int PRIVATE_KEY_SIZE = 279; // const unsigned int PUBLIC_KEY_SIZE = 65; @@ -40,12 +20,6 @@ // see www.keylength.com // script supports up to 75 for single byte push -class key_error : public std::runtime_error -{ -public: - explicit key_error(const std::string& str) : std::runtime_error(str) {} -}; - /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { @@ -65,100 +39,218 @@ public: /** An encapsulated public key. */ class CPubKey { private: - std::vector vchPubKey; - friend class CKey; + // Just store the serialized data. + // Its length can very cheaply be computed from the first byte. + unsigned char vch[65]; + + // Compute the length of a pubkey with a given first byte. + unsigned int static GetLen(unsigned char chHeader) { + if (chHeader == 2 || chHeader == 3) + return 33; + if (chHeader == 4 || chHeader == 6 || chHeader == 7) + return 65; + return 0; + } + + // Set this key data to be invalid + void Invalidate() { + vch[0] = 0xFF; + } public: - CPubKey() { } - CPubKey(const std::vector &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } - friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } - friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } - friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; } + // Construct an invalid public key. + CPubKey() { + Invalidate(); + } - IMPLEMENT_SERIALIZE( - READWRITE(vchPubKey); - ) + // Initialize a public key using begin/end iterators to byte data. + template + void Set(const T pbegin, const T pend) { + int len = pend == pbegin ? 0 : GetLen(pbegin[0]); + if (len && len == (pend-pbegin)) + memcpy(vch, (unsigned char*)&pbegin[0], len); + else + Invalidate(); + } + // Construct a public key using begin/end iterators to byte data. + template + CPubKey(const T pbegin, const T pend) { + Set(pbegin, pend); + } + + // Construct a public key from a byte vector. + CPubKey(const std::vector &vch) { + Set(vch.begin(), vch.end()); + } + + // Simple read-only vector-like interface to the pubkey data. + unsigned int size() const { return GetLen(vch[0]); } + const unsigned char *begin() const { return vch; } + const unsigned char *end() const { return vch+size(); } + const unsigned char &operator[](unsigned int pos) const { return vch[pos]; } + + // Comparator implementation. + friend bool operator==(const CPubKey &a, const CPubKey &b) { + return a.vch[0] == b.vch[0] && + memcmp(a.vch, b.vch, a.size()) == 0; + } + friend bool operator!=(const CPubKey &a, const CPubKey &b) { + return !(a == b); + } + friend bool operator<(const CPubKey &a, const CPubKey &b) { + return a.vch[0] < b.vch[0] || + (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0); + } + + // Implement serialization, as if this was a byte vector. + unsigned int GetSerializeSize(int nType, int nVersion) const { + return size() + 1; + } + template void Serialize(Stream &s, int nType, int nVersion) const { + unsigned int len = size(); + ::WriteCompactSize(s, len); + s.write((char*)vch, len); + } + template void Unserialize(Stream &s, int nType, int nVersion) { + unsigned int len = ::ReadCompactSize(s); + if (len <= 65) { + s.read((char*)vch, len); + } else { + // invalid pubkey, skip available data + char dummy; + while (len--) + s.read(&dummy, 1); + Invalidate(); + } + } + + // Get the KeyID of this public key (hash of its serialization) CKeyID GetID() const { - return CKeyID(Hash160(vchPubKey)); + return CKeyID(Hash160(vch, vch+size())); } + // Get the 256-bit hash of this public key. uint256 GetHash() const { - return Hash(vchPubKey.begin(), vchPubKey.end()); + return Hash(vch, vch+size()); } + // just check syntactic correctness. bool IsValid() const { - return vchPubKey.size() == 33 || vchPubKey.size() == 65; + return size() > 0; } + // fully validate whether this is a valid public key (more expensive than IsValid()) + bool IsFullyValid() const; + + // Check whether this is a compressed public key. bool IsCompressed() const { - return vchPubKey.size() == 33; + return size() == 33; } - std::vector Raw() const { - return vchPubKey; - } + // Verify a DER signature (~72 bytes). + // If this public key is not fully valid, the return value will be false. + bool Verify(const uint256 &hash, const std::vector& vchSig) const; + + // Verify a compact signature (~65 bytes). + // See CKey::SignCompact. + bool VerifyCompact(const uint256 &hash, const std::vector& vchSig) const; + + // Recover a public key from a compact signature. + bool RecoverCompact(const uint256 &hash, const std::vector& vchSig); + + // Turn this public key into an uncompressed public key. + bool Decompress(); }; -// secure_allocator is defined in serialize.h +// secure_allocator is defined in allocators.h // CPrivKey is a serialized private key, with all parameters included (279 bytes) typedef std::vector > CPrivKey; -// CSecret is a serialization of just the secret parameter (32 bytes) -typedef std::vector > CSecret; -/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ -class CKey -{ -protected: - EC_KEY* pkey; - bool fSet; - bool fCompressedPubKey; +/** An encapsulated private key. */ +class CKey { +private: + // Whether this private key is valid. We check for correctness when modifying the key + // data, so fValid should always correspond to the actual state. + bool fValid; - void SetCompressedPubKey(); + // Whether the public key corresponding to this private key is (to be) compressed. + bool fCompressed; + // The actual byte data + unsigned char vch[32]; + + // Check whether the 32-byte array pointed to be vch is valid keydata. + bool static Check(const unsigned char *vch); public: - void Reset(); + // Construct an invalid private key. + CKey() : fValid(false) { + LockObject(vch); + } - CKey(); - CKey(const CKey& b); + // 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)); + } - CKey& operator=(const CKey& b); + // Destructor (again necessary because of memlocking). + ~CKey() { + UnlockObject(vch); + } - ~CKey(); + // Initialize using begin and end iterators to byte data. + template + void Set(const T pbegin, const T pend, bool fCompressedIn) { + if (pend - pbegin != 32) { + fValid = false; + return; + } + if (Check(&pbegin[0])) { + memcpy(vch, (unsigned char*)&pbegin[0], 32); + fValid = true; + fCompressed = fCompressedIn; + } else { + fValid = false; + } + } - bool IsNull() const; - bool IsCompressed() const; + // 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(); } + // Check whether this private key is valid. + bool IsValid() const { return fValid; } + + // 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); - bool SetPrivKey(const CPrivKey& vchPrivKey); - bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); - CSecret GetSecret(bool &fCompressed) const; + + // Convert the private key to a CPrivKey (serialized OpenSSL private key data). + // This is expensive. CPrivKey GetPrivKey() const; - bool SetPubKey(const CPubKey& vchPubKey); + + // Compute the public key from a private key. + // This is expensive. CPubKey GetPubKey() const; - bool Sign(uint256 hash, std::vector& vchSig); + // Create a DER-serialized signature. + bool Sign(const uint256 &hash, std::vector& vchSig) const; - // create a compact signature (65 bytes), which allows reconstructing the used public key + // Create a compact signature (65 bytes), which allows reconstructing the used public key. // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, - // 0x1D = second key with even y, 0x1E = second key with odd y - bool SignCompact(uint256 hash, std::vector& vchSig); - - // reconstruct public key from a compact signature - // This is only slightly more CPU intensive than just verifying it. - // If this function succeeds, the recovered public key is guaranteed to be valid - // (the signature is a valid signature of the given data for that key) - bool SetCompactSignature(uint256 hash, const std::vector& vchSig); - - bool Verify(uint256 hash, const std::vector& vchSig); - - // Verify a compact signature - bool VerifyCompact(uint256 hash, const std::vector& vchSig); - - bool IsValid(); + // 0x1D = second key with even y, 0x1E = second key with odd y, + // add 0x04 for compressed keys. + bool SignCompact(const uint256 &hash, std::vector& vchSig) const; }; #endif diff --git a/src/keystore.cpp b/src/keystore.cpp index 5251703..808f8c2 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,61 +15,50 @@ bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const return true; } -bool CBasicKeyStore::AddKey(const CKey& key) +bool CKeyStore::AddKey(const CKey &key) { + return AddKeyPubKey(key, key.GetPubKey()); +} + +bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) { - bool fCompressed = false; - CSecret secret = key.GetSecret(fCompressed); - { - LOCK(cs_KeyStore); - mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed); - } + LOCK(cs_KeyStore); + mapKeys[pubkey.GetID()] = key; return true; } bool CBasicKeyStore::AddCScript(const CScript& redeemScript) { - { - LOCK(cs_KeyStore); - mapScripts[redeemScript.GetID()] = redeemScript; - } + LOCK(cs_KeyStore); + mapScripts[redeemScript.GetID()] = redeemScript; return true; } bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const { - bool result; - { - LOCK(cs_KeyStore); - result = (mapScripts.count(hash) > 0); - } - return result; + LOCK(cs_KeyStore); + return mapScripts.count(hash) > 0; } - bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const { + LOCK(cs_KeyStore); + ScriptMap::const_iterator mi = mapScripts.find(hash); + if (mi != mapScripts.end()) { - LOCK(cs_KeyStore); - ScriptMap::const_iterator mi = mapScripts.find(hash); - if (mi != mapScripts.end()) - { - redeemScriptOut = (*mi).second; - return true; - } + redeemScriptOut = (*mi).second; + return true; } return false; } bool CCryptoKeyStore::SetCrypted() { - { - LOCK(cs_KeyStore); - if (fUseCrypto) - return true; - if (!mapKeys.empty()) - return false; - fUseCrypto = true; - } + LOCK(cs_KeyStore); + if (fUseCrypto) + return true; + if (!mapKeys.empty()) + return false; + fUseCrypto = true; return true; } @@ -101,14 +88,13 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) { const CPubKey &vchPubKey = (*mi).second.first; const std::vector &vchCryptedSecret = (*mi).second.second; - CSecret vchSecret; + CKeyingMaterial vchSecret; if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) return false; if (vchSecret.size() != 32) return false; CKey key; - key.SetPubKey(vchPubKey); - key.SetSecret(vchSecret); + key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); if (key.GetPubKey() == vchPubKey) break; return false; @@ -119,23 +105,22 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) return true; } -bool CCryptoKeyStore::AddKey(const CKey& key) +bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) { { LOCK(cs_KeyStore); if (!IsCrypted()) - return CBasicKeyStore::AddKey(key); + return CBasicKeyStore::AddKeyPubKey(key, pubkey); if (IsLocked()) return false; std::vector vchCryptedSecret; - CPubKey vchPubKey = key.GetPubKey(); - bool fCompressed; - if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret)) + CKeyingMaterial vchSecret(key.begin(), key.end()); + if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) return false; - if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) + if (!AddCryptedKey(pubkey, vchCryptedSecret)) return false; } return true; @@ -166,13 +151,12 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const { const CPubKey &vchPubKey = (*mi).second.first; const std::vector &vchCryptedSecret = (*mi).second.second; - CSecret vchSecret; + CKeyingMaterial vchSecret; if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) return false; if (vchSecret.size() != 32) return false; - keyOut.SetPubKey(vchPubKey); - keyOut.SetSecret(vchSecret); + keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); return true; } } @@ -206,13 +190,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) fUseCrypto = true; BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys) { - CKey key; - if (!key.SetSecret(mKey.second.first, mKey.second.second)) - return false; - const CPubKey vchPubKey = key.GetPubKey(); + const CKey &key = mKey.second; + CPubKey vchPubKey = key.GetPubKey(); + CKeyingMaterial vchSecret(key.begin(), key.end()); std::vector vchCryptedSecret; - bool fCompressed; - if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret)) + if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) return false; if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; diff --git a/src/keystore.h b/src/keystore.h index 3cd6db4..49a7bf5 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KEYSTORE_H @@ -23,7 +21,8 @@ public: virtual ~CKeyStore() {} // Add a key to the store. - virtual bool AddKey(const CKey& key) =0; + virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0; + virtual bool AddKey(const CKey &key); // Check whether a key corresponding to a given address is present in the store. virtual bool HaveKey(const CKeyID &address) const =0; @@ -35,18 +34,9 @@ public: virtual bool AddCScript(const CScript& redeemScript) =0; virtual bool HaveCScript(const CScriptID &hash) const =0; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0; - - virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const - { - CKey key; - if (!GetKey(address, key)) - return false; - vchSecret = key.GetSecret(fCompressed); - return true; - } }; -typedef std::map > KeyMap; +typedef std::map KeyMap; typedef std::map ScriptMap; /** Basic key store, that keeps keys in an address->secret map */ @@ -57,7 +47,7 @@ protected: ScriptMap mapScripts; public: - bool AddKey(const CKey& key); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); bool HaveKey(const CKeyID &address) const { bool result; @@ -87,8 +77,7 @@ public: KeyMap::const_iterator mi = mapKeys.find(address); if (mi != mapKeys.end()) { - keyOut.Reset(); - keyOut.SetSecret((*mi).second.first, (*mi).second.second); + keyOut = mi->second; return true; } } @@ -148,7 +137,7 @@ public: bool Lock(); virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - bool AddKey(const CKey& key); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); bool HaveKey(const CKeyID &address) const { { diff --git a/src/leveldb.cpp b/src/leveldb.cpp new file mode 100644 index 0000000..e66f851 --- /dev/null +++ b/src/leveldb.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "leveldb.h" +#include "util.h" + +#include +#include +#include +#include + +#include + +void HandleError(const leveldb::Status &status) throw(leveldb_error) { + if (status.ok()) + return; + if (status.IsCorruption()) + throw leveldb_error("Database corrupted"); + if (status.IsIOError()) + throw leveldb_error("Database I/O error"); + if (status.IsNotFound()) + throw leveldb_error("Database entry missing"); + throw leveldb_error("Unknown database error"); +} + +static leveldb::Options GetOptions(size_t nCacheSize) { + leveldb::Options options; + options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); + options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously + options.filter_policy = leveldb::NewBloomFilterPolicy(10); + options.compression = leveldb::kNoCompression; + options.max_open_files = 64; + return options; +} + +CLevelDB::CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory, bool fWipe) { + penv = NULL; + readoptions.verify_checksums = true; + iteroptions.verify_checksums = true; + iteroptions.fill_cache = false; + syncoptions.sync = true; + options = GetOptions(nCacheSize); + options.create_if_missing = true; + if (fMemory) { + penv = leveldb::NewMemEnv(leveldb::Env::Default()); + options.env = penv; + } else { + if (fWipe) { + printf("Wiping LevelDB in %s\n", path.string().c_str()); + leveldb::DestroyDB(path.string(), options); + } + boost::filesystem::create_directory(path); + printf("Opening LevelDB in %s\n", path.string().c_str()); + } + leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); + if (!status.ok()) + throw std::runtime_error(strprintf("CLevelDB(): error opening database environment %s", status.ToString().c_str())); + printf("Opened LevelDB successfully\n"); +} + +CLevelDB::~CLevelDB() { + delete pdb; + pdb = NULL; + delete options.filter_policy; + options.filter_policy = NULL; + delete options.block_cache; + options.block_cache = NULL; + delete penv; + options.env = NULL; +} + +bool CLevelDB::WriteBatch(CLevelDBBatch &batch, bool fSync) throw(leveldb_error) { + leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); + if (!status.ok()) { + printf("LevelDB write failure: %s\n", status.ToString().c_str()); + HandleError(status); + return false; + } + return true; +} diff --git a/src/leveldb.h b/src/leveldb.h new file mode 100644 index 0000000..79262ed --- /dev/null +++ b/src/leveldb.h @@ -0,0 +1,153 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_LEVELDB_H +#define BITCOIN_LEVELDB_H + +#include "serialize.h" + +#include +#include + +#include + +class leveldb_error : public std::runtime_error +{ +public: + leveldb_error(const std::string &msg) : std::runtime_error(msg) {} +}; + +void HandleError(const leveldb::Status &status) throw(leveldb_error); + +// Batch of changes queued to be written to a CLevelDB +class CLevelDBBatch +{ + friend class CLevelDB; + +private: + leveldb::WriteBatch batch; + +public: + template void Write(const K& key, const V& value) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + ssValue.reserve(ssValue.GetSerializeSize(value)); + ssValue << value; + leveldb::Slice slValue(&ssValue[0], ssValue.size()); + + batch.Put(slKey, slValue); + } + + template void Erase(const K& key) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + batch.Delete(slKey); + } +}; + +class CLevelDB +{ +private: + // custom environment this database is using (may be NULL in case of default environment) + leveldb::Env *penv; + + // database options used + leveldb::Options options; + + // options used when reading from the database + leveldb::ReadOptions readoptions; + + // options used when iterating over values of the database + leveldb::ReadOptions iteroptions; + + // options used when writing to the database + leveldb::WriteOptions writeoptions; + + // options used when sync writing to the database + leveldb::WriteOptions syncoptions; + + // the database itself + leveldb::DB *pdb; + +public: + CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); + ~CLevelDB(); + + template bool Read(const K& key, V& value) throw(leveldb_error) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + std::string strValue; + leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + printf("LevelDB read failure: %s\n", status.ToString().c_str()); + HandleError(status); + } + try { + CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); + ssValue >> value; + } catch(std::exception &e) { + return false; + } + return true; + } + + template bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) { + CLevelDBBatch batch; + batch.Write(key, value); + return WriteBatch(batch, fSync); + } + + template bool Exists(const K& key) throw(leveldb_error) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + std::string strValue; + leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + printf("LevelDB read failure: %s\n", status.ToString().c_str()); + HandleError(status); + } + return true; + } + + template bool Erase(const K& key, bool fSync = false) throw(leveldb_error) { + CLevelDBBatch batch; + batch.Erase(key); + return WriteBatch(batch, fSync); + } + + bool WriteBatch(CLevelDBBatch &batch, bool fSync = false) throw(leveldb_error); + + // not available for LevelDB; provide for compatibility with BDB + bool Flush() { + return true; + } + + bool Sync() throw(leveldb_error) { + CLevelDBBatch batch; + return WriteBatch(batch, true); + } + + // not exactly clean encapsulation, but it's easiest for now + leveldb::Iterator *NewIterator() { + return pdb->NewIterator(iteroptions); + } +}; + +#endif // BITCOIN_LEVELDB_H diff --git a/src/leveldb/.gitignore b/src/leveldb/.gitignore new file mode 100644 index 0000000..71d87a4 --- /dev/null +++ b/src/leveldb/.gitignore @@ -0,0 +1,13 @@ +build_config.mk +*.a +*.o +*.dylib* +*.so +*.so.* +*_test +db_bench +leveldbutil +Release +Debug +Benchmark +vs2010.* diff --git a/src/leveldb/AUTHORS b/src/leveldb/AUTHORS new file mode 100644 index 0000000..fc40194 --- /dev/null +++ b/src/leveldb/AUTHORS @@ -0,0 +1,11 @@ +# Names should be added to this file like so: +# Name or Organization + +Google Inc. + +# Initial version authors: +Jeffrey Dean +Sanjay Ghemawat + +# Partial list of contributors: +Kevin Regan diff --git a/src/leveldb/LICENSE b/src/leveldb/LICENSE new file mode 100644 index 0000000..8e80208 --- /dev/null +++ b/src/leveldb/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/leveldb/NEWS b/src/leveldb/NEWS new file mode 100644 index 0000000..3fd9924 --- /dev/null +++ b/src/leveldb/NEWS @@ -0,0 +1,17 @@ +Release 1.2 2011-05-16 +---------------------- + +Fixes for larger databases (tested up to one billion 100-byte entries, +i.e., ~100GB). + +(1) Place hard limit on number of level-0 files. This fixes errors +of the form "too many open files". + +(2) Fixed memtable management. Before the fix, a heavy write burst +could cause unbounded memory usage. + +A fix for a logging bug where the reader would incorrectly complain +about corruption. + +Allow public access to WriteBatch contents so that users can easily +wrap a DB. diff --git a/src/leveldb/README b/src/leveldb/README new file mode 100644 index 0000000..3618ade --- /dev/null +++ b/src/leveldb/README @@ -0,0 +1,51 @@ +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/TODO b/src/leveldb/TODO new file mode 100644 index 0000000..e603c07 --- /dev/null +++ b/src/leveldb/TODO @@ -0,0 +1,14 @@ +ss +- Stats + +db +- Maybe implement DB::BulkDeleteForRange(start_key, end_key) + that would blow away files whose ranges are entirely contained + within [start_key..end_key]? For Chrome, deletion of obsolete + object stores, etc. can be done in the background anyway, so + probably not that important. +- There have been requests for MultiGet. + +After a range is completely deleted, what gets rid of the +corresponding files if we do no future changes to that range. Make +the conditions for triggering compactions fire in more situations? diff --git a/src/leveldb/WINDOWS.md b/src/leveldb/WINDOWS.md new file mode 100644 index 0000000..5b76c24 --- /dev/null +++ b/src/leveldb/WINDOWS.md @@ -0,0 +1,39 @@ +# Building LevelDB On Windows + +## Prereqs + +Install the [Windows Software Development Kit version 7.1](http://www.microsoft.com/downloads/dlx/en-us/listdetailsview.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b). + +Download and extract the [Snappy source distribution](http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz) + +1. Open the "Windows SDK 7.1 Command Prompt" : + Start Menu -> "Microsoft Windows SDK v7.1" > "Windows SDK 7.1 Command Prompt" +2. Change the directory to the leveldb project + +## Building the Static lib + +* 32 bit Version + + setenv /x86 + msbuild.exe /p:Configuration=Release /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 + +* 64 bit Version + + setenv /x64 + msbuild.exe /p:Configuration=Release /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 + + +## Building and Running the Benchmark app + +* 32 bit Version + + setenv /x86 + msbuild.exe /p:Configuration=Benchmark /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 + Benchmark\leveldb.exe + +* 64 bit Version + + setenv /x64 + msbuild.exe /p:Configuration=Benchmark /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 + x64\Benchmark\leveldb.exe + diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform new file mode 100644 index 0000000..bdfd641 --- /dev/null +++ b/src/leveldb/build_detect_platform @@ -0,0 +1,214 @@ +#!/bin/sh +# +# Detects OS we're compiling on and outputs a file specified by the first +# argument, which in turn gets read while processing Makefile. +# +# The output will set the following variables: +# CC C Compiler path +# CXX C++ Compiler path +# PLATFORM_LDFLAGS Linker flags +# PLATFORM_LIBS Libraries flags +# PLATFORM_SHARED_EXT Extension for shared libraries +# PLATFORM_SHARED_LDFLAGS Flags for building shared library +# This flag is embedded just before the name +# of the shared library without intervening spaces +# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library +# PLATFORM_CCFLAGS C compiler flags +# PLATFORM_CXXFLAGS C++ compiler flags. Will contain: +# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned +# shared libraries, empty otherwise. +# +# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following: +# +# -DLEVELDB_CSTDATOMIC_PRESENT if is present +# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms +# -DSNAPPY if the Snappy library is present +# + +OUTPUT=$1 +PREFIX=$2 +if test -z "$OUTPUT" || test -z "$PREFIX"; then + echo "usage: $0 " >&2 + exit 1 +fi + +# Delete existing output, if it exists +rm -f $OUTPUT +touch $OUTPUT + +if test -z "$CC"; then + CC=cc +fi + +if test -z "$CXX"; then + CXX=g++ +fi + +if test -z "$TMPDIR"; then + TMPDIR=/tmp +fi + +# Detect OS +if test -z "$TARGET_OS"; then + TARGET_OS=`uname -s` +fi + +COMMON_FLAGS= +CROSS_COMPILE= +PLATFORM_CCFLAGS= +PLATFORM_CXXFLAGS= +PLATFORM_LDFLAGS= +PLATFORM_LIBS= +PLATFORM_SHARED_EXT="so" +PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," +PLATFORM_SHARED_CFLAGS="-fPIC" +PLATFORM_SHARED_VERSIONED=true + +MEMCMP_FLAG= +if [ "$CXX" = "g++" ]; then + # Use libc's memcmp instead of GCC's memcmp. This results in ~40% + # performance improvement on readrandom under gcc 4.4.3 on Linux/x86. + MEMCMP_FLAG="-fno-builtin-memcmp" +fi + +case "$TARGET_OS" in + Darwin) + PLATFORM=OS_MACOSX + COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" + PLATFORM_SHARED_EXT=dylib + [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` + PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/" + PORT_FILE=port/port_posix.cc + ;; + Linux) + PLATFORM=OS_LINUX + COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + ;; + SunOS) + PLATFORM=OS_SOLARIS + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS" + PLATFORM_LIBS="-lpthread -lrt" + PORT_FILE=port/port_posix.cc + ;; + FreeBSD) + PLATFORM=OS_FREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; + GNU/kFreeBSD) + PLATFORM=OS_KFREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_KFREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; + NetBSD) + PLATFORM=OS_NETBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" + PLATFORM_LIBS="-lpthread -lgcc_s" + PORT_FILE=port/port_posix.cc + ;; + OpenBSD) + PLATFORM=OS_OPENBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + ;; + DragonFly) + PLATFORM=OS_DRAGONFLYBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; + OS_ANDROID_CROSSCOMPILE) + PLATFORM=OS_ANDROID + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" + PLATFORM_LDFLAGS="" # All pthread features are in the Android C library + PORT_FILE=port/port_posix.cc + CROSS_COMPILE=true + ;; + HP-UX) + PLATFORM=OS_HPUX + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + # man ld: +h internal_name + PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl," + ;; + OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) + PLATFORM=OS_WINDOWS + COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1" + PLATFORM_SOURCES="util/env_win.cc" + PLATFORM_LIBS="-lshlwapi" + PORT_FILE=port/port_win.cc + CROSS_COMPILE=true + ;; + *) + echo "Unknown platform!" >&2 + exit 1 +esac + +# We want to make a list of all cc files within util, db, table, and helpers +# except for the test and benchmark files. By default, find will output a list +# of all files matching either rule, so we need to append -print to make the +# prune take effect. +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" +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 + +# The sources consist of the portable files, plus the platform-specific port +# file. +echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT +echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT + +if [ "$CROSS_COMPILE" = "true" ]; then + # Cross-compiling; do not try any compilation tests. + true +else + CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$" + + # If -std=c++0x works, use . Otherwise use port_posix.h. + $CXX $CXXFLAGS -std=c++0x -x c++ - -o $CXXOUTPUT 2>/dev/null < + int main() {} +EOF + if [ "$?" = 0 ]; then + COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_CSTDATOMIC_PRESENT" + PLATFORM_CXXFLAGS="-std=c++0x" + else + COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX" + fi + + # Test whether tcmalloc is available + $CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -ltcmalloc 2>/dev/null </dev/null +fi + +PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS" +PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS" + +echo "CC=$CC" >> $OUTPUT +echo "CXX=$CXX" >> $OUTPUT +echo "PLATFORM=$PLATFORM" >> $OUTPUT +echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT +echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT +echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT +echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT +echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT diff --git a/src/leveldb/db/autocompact_test.cc b/src/leveldb/db/autocompact_test.cc new file mode 100644 index 0000000..d20a236 --- /dev/null +++ b/src/leveldb/db/autocompact_test.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "db/db_impl.h" +#include "leveldb/cache.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class AutoCompactTest { + public: + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + AutoCompactTest() { + dbname_ = test::TmpDir() + "/autocompact_test"; + tiny_cache_ = NewLRUCache(100); + options_.block_cache = tiny_cache_; + DestroyDB(dbname_, options_); + options_.create_if_missing = true; + options_.compression = kNoCompression; + ASSERT_OK(DB::Open(options_, dbname_, &db_)); + } + + ~AutoCompactTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void DoReads(int n); +}; + +static const int kValueSize = 200 * 1024; +static const int kTotalSize = 100 * 1024 * 1024; +static const int kCount = kTotalSize / kValueSize; + +// Read through the first n keys repeatedly and check that they get +// compacted (verified by checking the size of the key space). +void AutoCompactTest::DoReads(int n) { + std::string value(kValueSize, 'x'); + DBImpl* dbi = reinterpret_cast(db_); + + // Fill database + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Put(WriteOptions(), Key(i), value)); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Delete everything + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Delete(WriteOptions(), Key(i))); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Get initial measurement of the space we will be reading. + const int64_t initial_size = Size(Key(0), Key(n)); + const int64_t initial_other_size = Size(Key(n), Key(kCount)); + + // Read until size drops significantly. + std::string limit_key = Key(n); + for (int read = 0; true; read++) { + ASSERT_LT(read, 100) << "Taking too long to compact"; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); + iter->Valid() && iter->key().ToString() < limit_key; + iter->Next()) { + // Drop data + } + delete iter; + // Wait a little bit to allow any triggered compactions to complete. + Env::Default()->SleepForMicroseconds(1000000); + uint64_t size = Size(Key(0), Key(n)); + fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", + read+1, size/1048576.0, Size(Key(n), Key(kCount))/1048576.0); + if (size <= initial_size/10) { + break; + } + } + + // Verify that the size of the key space not touched by the reads + // is pretty much unchanged. + const int64_t final_other_size = Size(Key(n), Key(kCount)); + ASSERT_LE(final_other_size, initial_other_size + 1048576); + ASSERT_GE(final_other_size, initial_other_size/5 - 1048576); +} + +TEST(AutoCompactTest, ReadAll) { + DoReads(kCount); +} + +TEST(AutoCompactTest, ReadHalf) { + DoReads(kCount/2); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/builder.cc b/src/leveldb/db/builder.cc new file mode 100644 index 0000000..f419882 --- /dev/null +++ b/src/leveldb/db/builder.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/builder.h" + +#include "db/filename.h" +#include "db/dbformat.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" + +namespace leveldb { + +Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta) { + Status s; + meta->file_size = 0; + iter->SeekToFirst(); + + std::string fname = TableFileName(dbname, meta->number); + if (iter->Valid()) { + WritableFile* file; + s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + + TableBuilder* builder = new TableBuilder(options, file); + meta->smallest.DecodeFrom(iter->key()); + for (; iter->Valid(); iter->Next()) { + Slice key = iter->key(); + meta->largest.DecodeFrom(key); + builder->Add(key, iter->value()); + } + + // Finish and check for builder errors + if (s.ok()) { + s = builder->Finish(); + if (s.ok()) { + meta->file_size = builder->FileSize(); + assert(meta->file_size > 0); + } + } else { + builder->Abandon(); + } + delete builder; + + // Finish and check for file errors + if (s.ok()) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; + file = NULL; + + if (s.ok()) { + // Verify that the table is usable + Iterator* it = table_cache->NewIterator(ReadOptions(), + meta->number, + meta->file_size); + s = it->status(); + delete it; + } + } + + // Check for input iterator errors + if (!iter->status().ok()) { + s = iter->status(); + } + + if (s.ok() && meta->file_size > 0) { + // Keep it + } else { + env->DeleteFile(fname); + } + return s; +} + +} // namespace leveldb diff --git a/src/leveldb/db/builder.h b/src/leveldb/db/builder.h new file mode 100644 index 0000000..62431fc --- /dev/null +++ b/src/leveldb/db/builder.h @@ -0,0 +1,34 @@ +// 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_BUILDER_H_ +#define STORAGE_LEVELDB_DB_BUILDER_H_ + +#include "leveldb/status.h" + +namespace leveldb { + +struct Options; +struct FileMetaData; + +class Env; +class Iterator; +class TableCache; +class VersionEdit; + +// Build a Table file from the contents of *iter. The generated file +// will be named according to meta->number. On success, the rest of +// *meta will be filled with metadata about the generated table. +// If no data is present in *iter, meta->file_size will be set to +// zero, and no Table file will be produced. +extern Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/src/leveldb/db/c.cc b/src/leveldb/db/c.cc new file mode 100644 index 0000000..08ff0ad --- /dev/null +++ b/src/leveldb/db/c.cc @@ -0,0 +1,595 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/c.h" + +#include +#include +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/write_batch.h" + +using leveldb::Cache; +using leveldb::Comparator; +using leveldb::CompressionType; +using leveldb::DB; +using leveldb::Env; +using leveldb::FileLock; +using leveldb::FilterPolicy; +using leveldb::Iterator; +using leveldb::kMajorVersion; +using leveldb::kMinorVersion; +using leveldb::Logger; +using leveldb::NewBloomFilterPolicy; +using leveldb::NewLRUCache; +using leveldb::Options; +using leveldb::RandomAccessFile; +using leveldb::Range; +using leveldb::ReadOptions; +using leveldb::SequentialFile; +using leveldb::Slice; +using leveldb::Snapshot; +using leveldb::Status; +using leveldb::WritableFile; +using leveldb::WriteBatch; +using leveldb::WriteOptions; + +extern "C" { + +struct leveldb_t { DB* rep; }; +struct leveldb_iterator_t { Iterator* rep; }; +struct leveldb_writebatch_t { WriteBatch rep; }; +struct leveldb_snapshot_t { const Snapshot* rep; }; +struct leveldb_readoptions_t { ReadOptions rep; }; +struct leveldb_writeoptions_t { WriteOptions rep; }; +struct leveldb_options_t { Options rep; }; +struct leveldb_cache_t { Cache* rep; }; +struct leveldb_seqfile_t { SequentialFile* rep; }; +struct leveldb_randomfile_t { RandomAccessFile* rep; }; +struct leveldb_writablefile_t { WritableFile* rep; }; +struct leveldb_logger_t { Logger* rep; }; +struct leveldb_filelock_t { FileLock* rep; }; + +struct leveldb_comparator_t : public Comparator { + void* state_; + void (*destructor_)(void*); + int (*compare_)( + void*, + const char* a, size_t alen, + const char* b, size_t blen); + const char* (*name_)(void*); + + virtual ~leveldb_comparator_t() { + (*destructor_)(state_); + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + // No-ops since the C binding does not support key shortening methods. + virtual void FindShortestSeparator(std::string*, const Slice&) const { } + virtual void FindShortSuccessor(std::string* key) const { } +}; + +struct leveldb_filterpolicy_t : public FilterPolicy { + void* state_; + void (*destructor_)(void*); + const char* (*name_)(void*); + char* (*create_)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length); + unsigned char (*key_match_)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length); + + virtual ~leveldb_filterpolicy_t() { + (*destructor_)(state_); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + std::vector key_pointers(n); + std::vector key_sizes(n); + for (int i = 0; i < n; i++) { + key_pointers[i] = keys[i].data(); + key_sizes[i] = keys[i].size(); + } + size_t len; + char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); + dst->append(filter, len); + free(filter); + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return (*key_match_)(state_, key.data(), key.size(), + filter.data(), filter.size()); + } +}; + +struct leveldb_env_t { + Env* rep; + bool is_default; +}; + +static bool SaveError(char** errptr, const Status& s) { + assert(errptr != NULL); + if (s.ok()) { + return false; + } else if (*errptr == NULL) { + *errptr = strdup(s.ToString().c_str()); + } else { + // TODO(sanjay): Merge with existing error? + free(*errptr); + *errptr = strdup(s.ToString().c_str()); + } + return true; +} + +static char* CopyString(const std::string& str) { + char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); + memcpy(result, str.data(), sizeof(char) * str.size()); + return result; +} + +leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr) { + DB* db; + if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { + return NULL; + } + leveldb_t* result = new leveldb_t; + result->rep = db; + return result; +} + +void leveldb_close(leveldb_t* db) { + delete db->rep; + delete db; +} + +void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr) { + SaveError(errptr, + db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); +} + +void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr) { + SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); +} + + +void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr) { + SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); +} + +char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr) { + char* result = NULL; + std::string tmp; + Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); + if (s.ok()) { + *vallen = tmp.size(); + result = CopyString(tmp); + } else { + *vallen = 0; + if (!s.IsNotFound()) { + SaveError(errptr, s); + } + } + return result; +} + +leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options) { + leveldb_iterator_t* result = new leveldb_iterator_t; + result->rep = db->rep->NewIterator(options->rep); + return result; +} + +const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db) { + leveldb_snapshot_t* result = new leveldb_snapshot_t; + result->rep = db->rep->GetSnapshot(); + return result; +} + +void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot) { + db->rep->ReleaseSnapshot(snapshot->rep); + delete snapshot; +} + +char* leveldb_property_value( + leveldb_t* db, + const char* propname) { + std::string tmp; + if (db->rep->GetProperty(Slice(propname), &tmp)) { + // We use strdup() since we expect human readable output. + return strdup(tmp.c_str()); + } else { + return NULL; + } +} + +void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes) { + Range* ranges = new Range[num_ranges]; + for (int i = 0; i < num_ranges; i++) { + ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); + ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); + } + db->rep->GetApproximateSizes(ranges, num_ranges, sizes); + delete[] ranges; +} + +void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len) { + Slice a, b; + db->rep->CompactRange( + // Pass NULL Slice if corresponding "const char*" is NULL + (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), + (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); +} + +void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, DestroyDB(name, options->rep)); +} + +void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, RepairDB(name, options->rep)); +} + +void leveldb_iter_destroy(leveldb_iterator_t* iter) { + delete iter->rep; + delete iter; +} + +unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { + return iter->rep->Valid(); +} + +void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { + iter->rep->SeekToFirst(); +} + +void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { + iter->rep->SeekToLast(); +} + +void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { + iter->rep->Seek(Slice(k, klen)); +} + +void leveldb_iter_next(leveldb_iterator_t* iter) { + iter->rep->Next(); +} + +void leveldb_iter_prev(leveldb_iterator_t* iter) { + iter->rep->Prev(); +} + +const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { + Slice s = iter->rep->key(); + *klen = s.size(); + return s.data(); +} + +const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { + Slice s = iter->rep->value(); + *vlen = s.size(); + return s.data(); +} + +void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { + SaveError(errptr, iter->rep->status()); +} + +leveldb_writebatch_t* leveldb_writebatch_create() { + return new leveldb_writebatch_t; +} + +void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { + delete b; +} + +void leveldb_writebatch_clear(leveldb_writebatch_t* b) { + b->rep.Clear(); +} + +void leveldb_writebatch_put( + leveldb_writebatch_t* b, + const char* key, size_t klen, + const char* val, size_t vlen) { + b->rep.Put(Slice(key, klen), Slice(val, vlen)); +} + +void leveldb_writebatch_delete( + leveldb_writebatch_t* b, + const char* key, size_t klen) { + b->rep.Delete(Slice(key, klen)); +} + +void leveldb_writebatch_iterate( + leveldb_writebatch_t* b, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)) { + class H : public WriteBatch::Handler { + public: + void* state_; + void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); + void (*deleted_)(void*, const char* k, size_t klen); + virtual void Put(const Slice& key, const Slice& value) { + (*put_)(state_, key.data(), key.size(), value.data(), value.size()); + } + virtual void Delete(const Slice& key) { + (*deleted_)(state_, key.data(), key.size()); + } + }; + H handler; + handler.state_ = state; + handler.put_ = put; + handler.deleted_ = deleted; + b->rep.Iterate(&handler); +} + +leveldb_options_t* leveldb_options_create() { + return new leveldb_options_t; +} + +void leveldb_options_destroy(leveldb_options_t* options) { + delete options; +} + +void leveldb_options_set_comparator( + leveldb_options_t* opt, + leveldb_comparator_t* cmp) { + opt->rep.comparator = cmp; +} + +void leveldb_options_set_filter_policy( + leveldb_options_t* opt, + leveldb_filterpolicy_t* policy) { + opt->rep.filter_policy = policy; +} + +void leveldb_options_set_create_if_missing( + leveldb_options_t* opt, unsigned char v) { + opt->rep.create_if_missing = v; +} + +void leveldb_options_set_error_if_exists( + leveldb_options_t* opt, unsigned char v) { + opt->rep.error_if_exists = v; +} + +void leveldb_options_set_paranoid_checks( + leveldb_options_t* opt, unsigned char v) { + opt->rep.paranoid_checks = v; +} + +void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { + opt->rep.env = (env ? env->rep : NULL); +} + +void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { + opt->rep.info_log = (l ? l->rep : NULL); +} + +void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { + opt->rep.write_buffer_size = s; +} + +void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { + opt->rep.max_open_files = n; +} + +void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { + opt->rep.block_cache = c->rep; +} + +void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { + opt->rep.block_size = s; +} + +void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { + opt->rep.block_restart_interval = n; +} + +void leveldb_options_set_compression(leveldb_options_t* opt, int t) { + opt->rep.compression = static_cast(t); +} + +leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)) { + leveldb_comparator_t* result = new leveldb_comparator_t; + result->state_ = state; + result->destructor_ = destructor; + result->compare_ = compare; + result->name_ = name; + return result; +} + +void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { + delete cmp; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)) { + leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; + result->state_ = state; + result->destructor_ = destructor; + result->create_ = create_filter; + result->key_match_ = key_may_match; + result->name_ = name; + return result; +} + +void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { + delete filter; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { + // Make a leveldb_filterpolicy_t, but override all of its methods so + // they delegate to a NewBloomFilterPolicy() instead of user + // supplied C functions. + struct Wrapper : public leveldb_filterpolicy_t { + const FilterPolicy* rep_; + ~Wrapper() { delete rep_; } + const char* Name() const { return rep_->Name(); } + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + return rep_->CreateFilter(keys, n, dst); + } + bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return rep_->KeyMayMatch(key, filter); + } + static void DoNothing(void*) { } + }; + Wrapper* wrapper = new Wrapper; + wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); + wrapper->state_ = NULL; + wrapper->destructor_ = &Wrapper::DoNothing; + return wrapper; +} + +leveldb_readoptions_t* leveldb_readoptions_create() { + return new leveldb_readoptions_t; +} + +void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { + delete opt; +} + +void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t* opt, + unsigned char v) { + opt->rep.verify_checksums = v; +} + +void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t* opt, unsigned char v) { + opt->rep.fill_cache = v; +} + +void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t* opt, + const leveldb_snapshot_t* snap) { + opt->rep.snapshot = (snap ? snap->rep : NULL); +} + +leveldb_writeoptions_t* leveldb_writeoptions_create() { + return new leveldb_writeoptions_t; +} + +void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { + delete opt; +} + +void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t* opt, unsigned char v) { + opt->rep.sync = v; +} + +leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { + leveldb_cache_t* c = new leveldb_cache_t; + c->rep = NewLRUCache(capacity); + return c; +} + +void leveldb_cache_destroy(leveldb_cache_t* cache) { + delete cache->rep; + delete cache; +} + +leveldb_env_t* leveldb_create_default_env() { + leveldb_env_t* result = new leveldb_env_t; + result->rep = Env::Default(); + result->is_default = true; + return result; +} + +void leveldb_env_destroy(leveldb_env_t* env) { + if (!env->is_default) delete env->rep; + delete env; +} + +void leveldb_free(void* ptr) { + free(ptr); +} + +int leveldb_major_version() { + return kMajorVersion; +} + +int leveldb_minor_version() { + return kMinorVersion; +} + +} // end extern "C" diff --git a/src/leveldb/db/c_test.c b/src/leveldb/db/c_test.c new file mode 100644 index 0000000..7cd5ee0 --- /dev/null +++ b/src/leveldb/db/c_test.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. */ + +#include "leveldb/c.h" + +#include +#include +#include +#include +#include +#include + +const char* phase = ""; +static char dbname[200]; + +static void StartPhase(const char* name) { + fprintf(stderr, "=== Test %s\n", name); + phase = name; +} + +static const char* GetTempDir(void) { + const char* ret = getenv("TEST_TMPDIR"); + if (ret == NULL || ret[0] == '\0') + ret = "/tmp"; + return ret; +} + +#define CheckNoError(err) \ + if ((err) != NULL) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ + abort(); \ + } + +#define CheckCondition(cond) \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ + abort(); \ + } + +static void CheckEqual(const char* expected, const char* v, size_t n) { + if (expected == NULL && v == NULL) { + // ok + } else if (expected != NULL && v != NULL && n == strlen(expected) && + memcmp(expected, v, n) == 0) { + // ok + return; + } else { + fprintf(stderr, "%s: expected '%s', got '%s'\n", + phase, + (expected ? expected : "(null)"), + (v ? v : "(null")); + abort(); + } +} + +static void Free(char** ptr) { + if (*ptr) { + free(*ptr); + *ptr = NULL; + } +} + +static void CheckGet( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, + const char* expected) { + char* err = NULL; + size_t val_len; + char* val; + val = leveldb_get(db, options, key, strlen(key), &val_len, &err); + CheckNoError(err); + CheckEqual(expected, val, val_len); + Free(&val); +} + +static void CheckIter(leveldb_iterator_t* iter, + const char* key, const char* val) { + size_t len; + const char* str; + str = leveldb_iter_key(iter, &len); + CheckEqual(key, str, len); + str = leveldb_iter_value(iter, &len); + CheckEqual(val, str, len); +} + +// Callback from leveldb_writebatch_iterate() +static void CheckPut(void* ptr, + const char* k, size_t klen, + const char* v, size_t vlen) { + int* state = (int*) ptr; + CheckCondition(*state < 2); + switch (*state) { + case 0: + CheckEqual("bar", k, klen); + CheckEqual("b", v, vlen); + break; + case 1: + CheckEqual("box", k, klen); + CheckEqual("c", v, vlen); + break; + } + (*state)++; +} + +// Callback from leveldb_writebatch_iterate() +static void CheckDel(void* ptr, const char* k, size_t klen) { + int* state = (int*) ptr; + CheckCondition(*state == 2); + CheckEqual("bar", k, klen); + (*state)++; +} + +static void CmpDestroy(void* arg) { } + +static int CmpCompare(void* arg, const char* a, size_t alen, + const char* b, size_t blen) { + int n = (alen < blen) ? alen : blen; + int r = memcmp(a, b, n); + if (r == 0) { + if (alen < blen) r = -1; + else if (alen > blen) r = +1; + } + return r; +} + +static const char* CmpName(void* arg) { + return "foo"; +} + +// Custom filter policy +static unsigned char fake_filter_result = 1; +static void FilterDestroy(void* arg) { } +static const char* FilterName(void* arg) { + return "TestFilter"; +} +static char* FilterCreate( + void* arg, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length) { + *filter_length = 4; + char* result = malloc(4); + memcpy(result, "fake", 4); + return result; +} +unsigned char FilterKeyMatch( + void* arg, + const char* key, size_t length, + const char* filter, size_t filter_length) { + CheckCondition(filter_length == 4); + CheckCondition(memcmp(filter, "fake", 4) == 0); + return fake_filter_result; +} + +int main(int argc, char** argv) { + leveldb_t* db; + leveldb_comparator_t* cmp; + leveldb_cache_t* cache; + leveldb_env_t* env; + leveldb_options_t* options; + leveldb_readoptions_t* roptions; + leveldb_writeoptions_t* woptions; + char* err = NULL; + int run = -1; + + CheckCondition(leveldb_major_version() >= 1); + CheckCondition(leveldb_minor_version() >= 1); + + snprintf(dbname, sizeof(dbname), + "%s/leveldb_c_test-%d", + GetTempDir(), + ((int) geteuid())); + + StartPhase("create_objects"); + cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); + env = leveldb_create_default_env(); + cache = leveldb_cache_create_lru(100000); + + options = leveldb_options_create(); + leveldb_options_set_comparator(options, cmp); + leveldb_options_set_error_if_exists(options, 1); + leveldb_options_set_cache(options, cache); + leveldb_options_set_env(options, env); + leveldb_options_set_info_log(options, NULL); + leveldb_options_set_write_buffer_size(options, 100000); + leveldb_options_set_paranoid_checks(options, 1); + leveldb_options_set_max_open_files(options, 10); + leveldb_options_set_block_size(options, 1024); + leveldb_options_set_block_restart_interval(options, 8); + leveldb_options_set_compression(options, leveldb_no_compression); + + roptions = leveldb_readoptions_create(); + leveldb_readoptions_set_verify_checksums(roptions, 1); + leveldb_readoptions_set_fill_cache(roptions, 0); + + woptions = leveldb_writeoptions_create(); + leveldb_writeoptions_set_sync(woptions, 1); + + StartPhase("destroy"); + leveldb_destroy_db(options, dbname, &err); + Free(&err); + + StartPhase("open_error"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + Free(&err); + + StartPhase("leveldb_free"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + leveldb_free(err); + err = NULL; + + StartPhase("open"); + leveldb_options_set_create_if_missing(options, 1); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + + StartPhase("put"); + leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactall"); + leveldb_compact_range(db, NULL, 0, NULL, 0); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactrange"); + leveldb_compact_range(db, "a", 1, "z", 1); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("writebatch"); + { + leveldb_writebatch_t* wb = leveldb_writebatch_create(); + leveldb_writebatch_put(wb, "foo", 3, "a", 1); + leveldb_writebatch_clear(wb); + leveldb_writebatch_put(wb, "bar", 3, "b", 1); + leveldb_writebatch_put(wb, "box", 3, "c", 1); + leveldb_writebatch_delete(wb, "bar", 3); + leveldb_write(db, woptions, wb, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + int pos = 0; + leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); + CheckCondition(pos == 3); + leveldb_writebatch_destroy(wb); + } + + StartPhase("iter"); + { + leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_first(iter); + CheckCondition(leveldb_iter_valid(iter)); + CheckIter(iter, "box", "c"); + leveldb_iter_next(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_prev(iter); + CheckIter(iter, "box", "c"); + leveldb_iter_prev(iter); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_last(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_seek(iter, "b", 1); + CheckIter(iter, "box", "c"); + leveldb_iter_get_error(iter, &err); + CheckNoError(err); + leveldb_iter_destroy(iter); + } + + StartPhase("approximate_sizes"); + { + int i; + int n = 20000; + char keybuf[100]; + char valbuf[100]; + uint64_t sizes[2]; + const char* start[2] = { "a", "k00000000000000010000" }; + size_t start_len[2] = { 1, 21 }; + const char* limit[2] = { "k00000000000000010000", "z" }; + size_t limit_len[2] = { 21, 1 }; + leveldb_writeoptions_set_sync(woptions, 0); + for (i = 0; i < n; i++) { + snprintf(keybuf, sizeof(keybuf), "k%020d", i); + snprintf(valbuf, sizeof(valbuf), "v%020d", i); + leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf), + &err); + CheckNoError(err); + } + leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes); + CheckCondition(sizes[0] > 0); + CheckCondition(sizes[1] > 0); + } + + StartPhase("property"); + { + char* prop = leveldb_property_value(db, "nosuchprop"); + CheckCondition(prop == NULL); + prop = leveldb_property_value(db, "leveldb.stats"); + CheckCondition(prop != NULL); + Free(&prop); + } + + StartPhase("snapshot"); + { + const leveldb_snapshot_t* snap; + snap = leveldb_create_snapshot(db); + leveldb_delete(db, woptions, "foo", 3, &err); + CheckNoError(err); + leveldb_readoptions_set_snapshot(roptions, snap); + CheckGet(db, roptions, "foo", "hello"); + leveldb_readoptions_set_snapshot(roptions, NULL); + CheckGet(db, roptions, "foo", NULL); + leveldb_release_snapshot(db, snap); + } + + StartPhase("repair"); + { + leveldb_close(db); + leveldb_options_set_create_if_missing(options, 0); + leveldb_options_set_error_if_exists(options, 0); + leveldb_repair_db(options, dbname, &err); + CheckNoError(err); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + leveldb_options_set_create_if_missing(options, 1); + leveldb_options_set_error_if_exists(options, 1); + } + + StartPhase("filter"); + for (run = 0; run < 2; run++) { + // First run uses custom filter, second run uses bloom filter + CheckNoError(err); + leveldb_filterpolicy_t* policy; + if (run == 0) { + policy = leveldb_filterpolicy_create( + NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName); + } else { + policy = leveldb_filterpolicy_create_bloom(10); + } + + // Create new database + leveldb_close(db); + leveldb_destroy_db(options, dbname, &err); + leveldb_options_set_filter_policy(options, policy); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err); + CheckNoError(err); + leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err); + CheckNoError(err); + leveldb_compact_range(db, NULL, 0, NULL, 0); + + fake_filter_result = 1; + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + if (phase == 0) { + // Must not find value when custom filter returns false + fake_filter_result = 0; + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + fake_filter_result = 1; + + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + } + leveldb_options_set_filter_policy(options, NULL); + leveldb_filterpolicy_destroy(policy); + } + + StartPhase("cleanup"); + leveldb_close(db); + leveldb_options_destroy(options); + leveldb_readoptions_destroy(roptions); + leveldb_writeoptions_destroy(woptions); + leveldb_cache_destroy(cache); + leveldb_comparator_destroy(cmp); + leveldb_env_destroy(env); + + fprintf(stderr, "PASS\n"); + return 0; +} diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc new file mode 100644 index 0000000..b37ffdf --- /dev/null +++ b/src/leveldb/db/corruption_test.cc @@ -0,0 +1,352 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include +#include +#include +#include +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/log_format.h" +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kValueSize = 1000; + +class CorruptionTest { + public: + test::ErrorEnv env_; + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + CorruptionTest() { + tiny_cache_ = NewLRUCache(100); + options_.env = &env_; + options_.block_cache = tiny_cache_; + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, options_); + + db_ = NULL; + options_.create_if_missing = true; + Reopen(); + options_.create_if_missing = false; + } + + ~CorruptionTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + Status TryReopen() { + delete db_; + db_ = NULL; + return DB::Open(options_, dbname_, &db_); + } + + void Reopen() { + ASSERT_OK(TryReopen()); + } + + void RepairDB() { + delete db_; + db_ = NULL; + ASSERT_OK(::leveldb::RepairDB(dbname_, options_)); + } + + void Build(int n) { + std::string key_space, value_space; + WriteBatch batch; + for (int i = 0; i < n; i++) { + //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n); + Slice key = Key(i, &key_space); + batch.Clear(); + batch.Put(key, Value(i, &value_space)); + ASSERT_OK(db_->Write(WriteOptions(), &batch)); + } + } + + void Check(int min_expected, int max_expected) { + int next_expected = 0; + int missed = 0; + int bad_keys = 0; + int bad_values = 0; + int correct = 0; + std::string value_space; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + uint64_t key; + Slice in(iter->key()); + if (in == "" || in == "~") { + // Ignore boundary keys. + continue; + } + if (!ConsumeDecimalNumber(&in, &key) || + !in.empty() || + key < next_expected) { + bad_keys++; + continue; + } + missed += (key - next_expected); + next_expected = key + 1; + if (iter->value() != Value(key, &value_space)) { + bad_values++; + } else { + correct++; + } + } + delete iter; + + fprintf(stderr, + "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n", + min_expected, max_expected, correct, bad_keys, bad_values, missed); + ASSERT_LE(min_expected, correct); + ASSERT_GE(max_expected, correct); + } + + void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) { + // Pick file to corrupt + std::vector filenames; + ASSERT_OK(env_.GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + std::string fname; + int picked_number = -1; + for (int i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type == filetype && + int(number) > picked_number) { // Pick latest file + fname = dbname_ + "/" + filenames[i]; + picked_number = number; + } + } + ASSERT_TRUE(!fname.empty()) << filetype; + + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + const char* msg = strerror(errno); + ASSERT_TRUE(false) << fname << ": " << msg; + } + + if (offset < 0) { + // Relative to end of file; make it absolute + if (-offset > sbuf.st_size) { + offset = 0; + } else { + offset = sbuf.st_size + offset; + } + } + if (offset > sbuf.st_size) { + offset = sbuf.st_size; + } + if (offset + bytes_to_corrupt > sbuf.st_size) { + bytes_to_corrupt = sbuf.st_size - offset; + } + + // Do it + std::string contents; + Status s = ReadFileToString(Env::Default(), fname, &contents); + ASSERT_TRUE(s.ok()) << s.ToString(); + for (int i = 0; i < bytes_to_corrupt; i++) { + contents[i + offset] ^= 0x80; + } + s = WriteStringToFile(Env::Default(), contents, fname); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + int Property(const std::string& name) { + std::string property; + int result; + if (db_->GetProperty(name, &property) && + sscanf(property.c_str(), "%d", &result) == 1) { + return result; + } else { + return -1; + } + } + + // Return the ith key + Slice Key(int i, std::string* storage) { + 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) { + Random r(k); + return test::RandomString(&r, kValueSize, storage); + } +}; + +TEST(CorruptionTest, Recovery) { + Build(100); + Check(100, 100); + Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record + Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block + Reopen(); + + // The 64 records in the first two log blocks are completely lost. + Check(36, 36); +} + +TEST(CorruptionTest, RecoverWriteError) { + env_.writable_file_error_ = true; + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); +} + +TEST(CorruptionTest, NewFileErrorDuringWrite) { + // Do enough writing to force minor compaction + env_.writable_file_error_ = true; + const int num = 3 + (Options().write_buffer_size / kValueSize); + std::string value_storage; + Status s; + for (int i = 0; s.ok() && i < num; i++) { + WriteBatch batch; + batch.Put("a", Value(100, &value_storage)); + s = db_->Write(WriteOptions(), &batch); + } + ASSERT_TRUE(!s.ok()); + ASSERT_GE(env_.num_writable_file_errors_, 1); + env_.writable_file_error_ = false; + Reopen(); +} + +TEST(CorruptionTest, TableFile) { + Build(100); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + dbi->TEST_CompactRange(1, NULL, NULL); + + Corrupt(kTableFile, 100, 1); + Check(90, 99); +} + +TEST(CorruptionTest, TableFileIndexData) { + Build(10000); // Enough to build multiple Tables + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + + Corrupt(kTableFile, -2000, 500); + Reopen(); + Check(5000, 9999); +} + +TEST(CorruptionTest, MissingDescriptor) { + Build(1000); + RepairDB(); + Reopen(); + Check(1000, 1000); +} + +TEST(CorruptionTest, SequenceNumberRecovery) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5")); + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v5", v); + // Write something. If sequence number was not recovered properly, + // it will be hidden by an earlier write. + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6")); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); + Reopen(); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); +} + +TEST(CorruptionTest, CorruptedDescriptor) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + + Corrupt(kDescriptorFile, 0, 1000); + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); + + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("hello", v); +} + +TEST(CorruptionTest, CompactionInputError) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); + + Corrupt(kTableFile, 100, 1); + Check(5, 9); + + // Force compactions by writing lots of values + Build(10000); + Check(10000, 10000); +} + +TEST(CorruptionTest, CompactionInputErrorParanoid) { + options_.paranoid_checks = true; + options_.write_buffer_size = 512 << 10; + Reopen(); + DBImpl* dbi = reinterpret_cast(db_); + + // Make multiple inputs so we need to compact. + for (int i = 0; i < 2; i++) { + Build(10); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + env_.SleepForMicroseconds(100000); + } + dbi->CompactRange(NULL, NULL); + + // Write must fail because of corrupted table + std::string tmp1, tmp2; + Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2)); + ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; +} + +TEST(CorruptionTest, UnrelatedKeys) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + + std::string tmp1, tmp2; + ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2))); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); + dbi->TEST_CompactMemTable(); + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc new file mode 100644 index 0000000..7abdf87 --- /dev/null +++ b/src/leveldb/db/db_bench.cc @@ -0,0 +1,979 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "db/db_impl.h" +#include "db/version_set.h" +#include "leveldb/cache.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/write_batch.h" +#include "port/port.h" +#include "util/crc32c.h" +#include "util/histogram.h" +#include "util/mutexlock.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillsync -- write N/100 values in random key order in sync mode +// fill100K -- write N/1000 100K values in random order in async mode +// deleteseq -- delete N keys in sequential order +// deleterandom -- delete N keys in random order +// readseq -- read N times sequentially +// readreverse -- read N times in reverse order +// readrandom -- read N times in random order +// readmissing -- read N missing keys in random order +// readhot -- read N times in random order from 1% section of DB +// seekrandom -- N random seeks +// crc32c -- repeated crc32c of 4K of data +// acquireload -- load N*1000 times +// Meta operations: +// compact -- Compact the entire DB +// stats -- Print DB stats +// sstables -- Print sstable info +// heapprofile -- Dump a heap profile (if supported by this port) +static const char* FLAGS_benchmarks = + "fillseq," + "fillsync," + "fillrandom," + "overwrite," + "readrandom," + "readrandom," // Extra run to allow previous compactions to quiesce + "readseq," + "readreverse," + "compact," + "readrandom," + "readseq," + "readreverse," + "fill100K," + "crc32c," + "snappycomp," + "snappyuncomp," + "acquireload," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Number of concurrent threads to run. +static int FLAGS_threads = 1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Number of bytes to buffer in memtable before compacting +// (initialized to default value by "main") +static int FLAGS_write_buffer_size = 0; + +// Number of bytes to use as a cache of uncompressed data. +// Negative means use default settings. +static int FLAGS_cache_size = -1; + +// Maximum number of files to keep open at the same time (use default if == 0) +static int FLAGS_open_files = 0; + +// Bloom filter bits per key. +// Negative means use default settings. +static int FLAGS_bloom_bits = -1; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +namespace leveldb { + +namespace { + +// Helper for quickly generating random data. +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +static void AppendWithSpace(std::string* str, Slice msg) { + if (msg.empty()) return; + if (!str->empty()) { + str->push_back(' '); + } + str->append(msg.data(), msg.size()); +} + +class Stats { + private: + double start_; + double finish_; + double seconds_; + int done_; + int next_report_; + int64_t bytes_; + double last_op_finish_; + Histogram hist_; + std::string message_; + + public: + Stats() { Start(); } + + void Start() { + next_report_ = 100; + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + bytes_ = 0; + seconds_ = 0; + start_ = Env::Default()->NowMicros(); + finish_ = start_; + message_.clear(); + } + + void Merge(const Stats& other) { + hist_.Merge(other.hist_); + done_ += other.done_; + bytes_ += other.bytes_; + seconds_ += other.seconds_; + if (other.start_ < start_) start_ = other.start_; + if (other.finish_ > finish_) finish_ = other.finish_; + + // Just keep the messages from one thread + if (message_.empty()) message_ = other.message_; + } + + void Stop() { + finish_ = Env::Default()->NowMicros(); + seconds_ = (finish_ - start_) * 1e-6; + } + + void AddMessage(Slice msg) { + AppendWithSpace(&message_, msg); + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros(); + double micros = now - last_op_finish_; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void AddBytes(int64_t n) { + bytes_ += n; + } + + void Report(const Slice& name) { + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + std::string extra; + if (bytes_ > 0) { + // Rate is computed on actual elapsed time, not the sum of per-thread + // elapsed times. + double elapsed = (finish_ - start_) * 1e-6; + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / elapsed); + extra = rate; + } + AppendWithSpace(&extra, message_); + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + seconds_ * 1e6 / done_, + (extra.empty() ? "" : " "), + extra.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } +}; + +// State shared by all concurrent executions of the same benchmark. +struct SharedState { + port::Mutex mu; + port::CondVar cv; + int total; + + // Each thread goes through the following states: + // (1) initializing + // (2) waiting for others to be initialized + // (3) running + // (4) done + + int num_initialized; + int num_done; + bool start; + + SharedState() : cv(&mu) { } +}; + +// Per-thread state for concurrent executions of the same benchmark. +struct ThreadState { + int tid; // 0..n-1 when running in n threads + Random rand; // Has different seeds for different threads + Stats stats; + SharedState* shared; + + ThreadState(int index) + : tid(index), + rand(1000 + index) { + } +}; + +} // namespace + +class Benchmark { + private: + Cache* cache_; + const FilterPolicy* filter_policy_; + DB* db_; + int num_; + int value_size_; + int entries_per_batch_; + WriteOptions write_options_; + int reads_; + int heap_counter_; + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + + // See if snappy is working by attempting to compress a compressible string + const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + std::string compressed; + if (!port::Snappy_Compress(text, sizeof(text), &compressed)) { + fprintf(stdout, "WARNING: Snappy compression is not enabled\n"); + } else if (compressed.size() >= sizeof(text)) { + fprintf(stdout, "WARNING: Snappy compression is not effective\n"); + } + } + + void PrintEnvironment() { + fprintf(stderr, "LevelDB: version %d.%d\n", + kMajorVersion, kMinorVersion); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + public: + Benchmark() + : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL), + filter_policy_(FLAGS_bloom_bits >= 0 + ? NewBloomFilterPolicy(FLAGS_bloom_bits) + : NULL), + db_(NULL), + num_(FLAGS_num), + value_size_(FLAGS_value_size), + entries_per_batch_(1), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + heap_counter_(0) { + std::vector files; + Env::Default()->GetChildren(FLAGS_db, &files); + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("heap-")) { + Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); + } + } + if (!FLAGS_use_existing_db) { + DestroyDB(FLAGS_db, Options()); + } + } + + ~Benchmark() { + delete db_; + delete cache_; + delete filter_policy_; + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + // Reset parameters that may be overriddden bwlow + num_ = FLAGS_num; + reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads); + value_size_ = FLAGS_value_size; + entries_per_batch_ = 1; + write_options_ = WriteOptions(); + + void (Benchmark::*method)(ThreadState*) = NULL; + bool fresh_db = false; + int num_threads = FLAGS_threads; + + if (name == Slice("fillseq")) { + fresh_db = true; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillbatch")) { + fresh_db = true; + entries_per_batch_ = 1000; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillrandom")) { + fresh_db = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("overwrite")) { + fresh_db = false; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fillsync")) { + fresh_db = true; + num_ /= 1000; + write_options_.sync = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fill100K")) { + fresh_db = true; + num_ /= 1000; + value_size_ = 100 * 1000; + method = &Benchmark::WriteRandom; + } else if (name == Slice("readseq")) { + method = &Benchmark::ReadSequential; + } else if (name == Slice("readreverse")) { + method = &Benchmark::ReadReverse; + } else if (name == Slice("readrandom")) { + method = &Benchmark::ReadRandom; + } else if (name == Slice("readmissing")) { + method = &Benchmark::ReadMissing; + } else if (name == Slice("seekrandom")) { + method = &Benchmark::SeekRandom; + } else if (name == Slice("readhot")) { + method = &Benchmark::ReadHot; + } else if (name == Slice("readrandomsmall")) { + reads_ /= 1000; + method = &Benchmark::ReadRandom; + } else if (name == Slice("deleteseq")) { + method = &Benchmark::DeleteSeq; + } else if (name == Slice("deleterandom")) { + method = &Benchmark::DeleteRandom; + } else if (name == Slice("readwhilewriting")) { + num_threads++; // Add extra thread for writing + method = &Benchmark::ReadWhileWriting; + } else if (name == Slice("compact")) { + method = &Benchmark::Compact; + } else if (name == Slice("crc32c")) { + method = &Benchmark::Crc32c; + } else if (name == Slice("acquireload")) { + method = &Benchmark::AcquireLoad; + } else if (name == Slice("snappycomp")) { + method = &Benchmark::SnappyCompress; + } else if (name == Slice("snappyuncomp")) { + method = &Benchmark::SnappyUncompress; + } else if (name == Slice("heapprofile")) { + HeapProfile(); + } else if (name == Slice("stats")) { + PrintStats("leveldb.stats"); + } else if (name == Slice("sstables")) { + PrintStats("leveldb.sstables"); + } else { + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + + if (fresh_db) { + if (FLAGS_use_existing_db) { + fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n", + name.ToString().c_str()); + method = NULL; + } else { + delete db_; + db_ = NULL; + DestroyDB(FLAGS_db, Options()); + Open(); + } + } + + if (method != NULL) { + RunBenchmark(num_threads, name, method); + } + } + } + + private: + struct ThreadArg { + Benchmark* bm; + SharedState* shared; + ThreadState* thread; + void (Benchmark::*method)(ThreadState*); + }; + + static void ThreadBody(void* v) { + ThreadArg* arg = reinterpret_cast(v); + SharedState* shared = arg->shared; + ThreadState* thread = arg->thread; + { + MutexLock l(&shared->mu); + shared->num_initialized++; + if (shared->num_initialized >= shared->total) { + shared->cv.SignalAll(); + } + while (!shared->start) { + shared->cv.Wait(); + } + } + + thread->stats.Start(); + (arg->bm->*(arg->method))(thread); + thread->stats.Stop(); + + { + MutexLock l(&shared->mu); + shared->num_done++; + if (shared->num_done >= shared->total) { + shared->cv.SignalAll(); + } + } + } + + void RunBenchmark(int n, Slice name, + void (Benchmark::*method)(ThreadState*)) { + SharedState shared; + shared.total = n; + shared.num_initialized = 0; + shared.num_done = 0; + shared.start = false; + + ThreadArg* arg = new ThreadArg[n]; + for (int i = 0; i < n; i++) { + arg[i].bm = this; + arg[i].method = method; + arg[i].shared = &shared; + arg[i].thread = new ThreadState(i); + arg[i].thread->shared = &shared; + Env::Default()->StartThread(ThreadBody, &arg[i]); + } + + shared.mu.Lock(); + while (shared.num_initialized < n) { + shared.cv.Wait(); + } + + shared.start = true; + shared.cv.SignalAll(); + while (shared.num_done < n) { + shared.cv.Wait(); + } + shared.mu.Unlock(); + + for (int i = 1; i < n; i++) { + arg[0].thread->stats.Merge(arg[i].thread->stats); + } + arg[0].thread->stats.Report(name); + + for (int i = 0; i < n; i++) { + delete arg[i].thread; + } + delete[] arg; + } + + void Crc32c(ThreadState* thread) { + // Checksum about 500MB of data total + const int size = 4096; + const char* label = "(4K per op)"; + std::string data(size, 'x'); + int64_t bytes = 0; + uint32_t crc = 0; + while (bytes < 500 * 1048576) { + crc = crc32c::Value(data.data(), size); + thread->stats.FinishedSingleOp(); + bytes += size; + } + // Print so result is not dead + fprintf(stderr, "... crc=0x%x\r", static_cast(crc)); + + thread->stats.AddBytes(bytes); + thread->stats.AddMessage(label); + } + + void AcquireLoad(ThreadState* thread) { + int dummy; + port::AtomicPointer ap(&dummy); + int count = 0; + void *ptr = NULL; + thread->stats.AddMessage("(each op is 1000 loads)"); + while (count < 100000) { + for (int i = 0; i < 1000; i++) { + ptr = ap.Acquire_Load(); + } + count++; + thread->stats.FinishedSingleOp(); + } + if (ptr == NULL) exit(1); // Disable unused variable warning. + } + + void SnappyCompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + int64_t bytes = 0; + int64_t produced = 0; + bool ok = true; + std::string compressed; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + produced += compressed.size(); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "(output: %.1f%%)", + (produced * 100.0) / bytes); + thread->stats.AddMessage(buf); + thread->stats.AddBytes(bytes); + } + } + + void SnappyUncompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + std::string compressed; + bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + int64_t bytes = 0; + char* uncompressed = new char[input.size()]; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Uncompress(compressed.data(), compressed.size(), + uncompressed); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + delete[] uncompressed; + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + thread->stats.AddBytes(bytes); + } + } + + void Open() { + assert(db_ == NULL); + Options options; + options.create_if_missing = !FLAGS_use_existing_db; + options.block_cache = cache_; + options.write_buffer_size = FLAGS_write_buffer_size; + options.max_open_files = FLAGS_open_files; + options.filter_policy = filter_policy_; + Status s = DB::Open(options, FLAGS_db, &db_); + if (!s.ok()) { + fprintf(stderr, "open error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + void WriteSeq(ThreadState* thread) { + DoWrite(thread, true); + } + + void WriteRandom(ThreadState* thread) { + DoWrite(thread, false); + } + + void DoWrite(ThreadState* thread, bool seq) { + if (num_ != FLAGS_num) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_); + thread->stats.AddMessage(msg); + } + + RandomGenerator gen; + WriteBatch batch; + Status s; + int64_t bytes = 0; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Put(key, gen.Generate(value_size_)); + bytes += value_size_ + strlen(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + thread->stats.AddBytes(bytes); + } + + void ReadSequential(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadReverse(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadRandom(ThreadState* thread) { + ReadOptions options; + std::string value; + int found = 0; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + if (db_->Get(options, key, &value).ok()) { + found++; + } + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void ReadMissing(ThreadState* thread) { + ReadOptions options; + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d.", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void ReadHot(ThreadState* thread) { + ReadOptions options; + std::string value; + const int range = (FLAGS_num + 99) / 100; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % range; + snprintf(key, sizeof(key), "%016d", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void SeekRandom(ThreadState* thread) { + ReadOptions options; + std::string value; + int found = 0; + for (int i = 0; i < reads_; i++) { + Iterator* iter = db_->NewIterator(options); + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + iter->Seek(key); + if (iter->Valid() && iter->key() == key) found++; + delete iter; + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void DoDelete(ThreadState* thread, bool seq) { + RandomGenerator gen; + WriteBatch batch; + Status s; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Delete(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "del error: %s\n", s.ToString().c_str()); + exit(1); + } + } + } + + void DeleteSeq(ThreadState* thread) { + DoDelete(thread, true); + } + + void DeleteRandom(ThreadState* thread) { + DoDelete(thread, false); + } + + void ReadWhileWriting(ThreadState* thread) { + if (thread->tid > 0) { + ReadRandom(thread); + } else { + // Special thread that keeps writing until other threads are done. + RandomGenerator gen; + while (true) { + { + MutexLock l(&thread->shared->mu); + if (thread->shared->num_done + 1 >= thread->shared->num_initialized) { + // Other threads have finished + break; + } + } + + const int k = thread->rand.Next() % FLAGS_num; + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + Status s = db_->Put(write_options_, key, gen.Generate(value_size_)); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + // Do not count any of the preceding work/delay in stats. + thread->stats.Start(); + } + } + + void Compact(ThreadState* thread) { + db_->CompactRange(NULL, NULL); + } + + void PrintStats(const char* key) { + std::string stats; + if (!db_->GetProperty(key, &stats)) { + stats = "(failed)"; + } + fprintf(stdout, "\n%s\n", stats.c_str()); + } + + static void WriteToFile(void* arg, const char* buf, int n) { + reinterpret_cast(arg)->Append(Slice(buf, n)); + } + + void HeapProfile() { + char fname[100]; + snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); + WritableFile* file; + Status s = Env::Default()->NewWritableFile(fname, &file); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + return; + } + bool ok = port::GetHeapProfile(WriteToFile, file); + delete file; + if (!ok) { + fprintf(stderr, "heap profiling not supported\n"); + Env::Default()->DeleteFile(fname); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; + FLAGS_open_files = leveldb::Options().max_open_files; + std::string default_db_path; + + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } 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], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) { + FLAGS_threads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { + FLAGS_write_buffer_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { + FLAGS_bloom_bits = n; + } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) { + FLAGS_open_files = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc new file mode 100644 index 0000000..fa13510 --- /dev/null +++ b/src/leveldb/db/db_impl.cc @@ -0,0 +1,1498 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" + +#include +#include +#include +#include +#include +#include +#include "db/builder.h" +#include "db/db_iter.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/table_builder.h" +#include "port/port.h" +#include "table/block.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" +#include "util/mutexlock.h" + +namespace leveldb { + +const int kNumNonTableCacheFiles = 10; + +// Information kept for every waiting writer +struct DBImpl::Writer { + Status status; + WriteBatch* batch; + bool sync; + bool done; + port::CondVar cv; + + explicit Writer(port::Mutex* mu) : cv(mu) { } +}; + +struct DBImpl::CompactionState { + Compaction* const compaction; + + // Sequence numbers < smallest_snapshot are not significant since we + // will never have to service a snapshot below smallest_snapshot. + // Therefore if we have seen a sequence number S <= smallest_snapshot, + // we can drop all entries for the same key with sequence numbers < S. + SequenceNumber smallest_snapshot; + + // Files produced by compaction + struct Output { + uint64_t number; + uint64_t file_size; + InternalKey smallest, largest; + }; + std::vector outputs; + + // State kept for output being generated + WritableFile* outfile; + TableBuilder* builder; + + uint64_t total_bytes; + + Output* current_output() { return &outputs[outputs.size()-1]; } + + explicit CompactionState(Compaction* c) + : compaction(c), + outfile(NULL), + builder(NULL), + total_bytes(0) { + } +}; + +// Fix user-supplied options to be reasonable +template +static void ClipToRange(T* ptr, V minvalue, V maxvalue) { + if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; + if (static_cast(*ptr) < minvalue) *ptr = minvalue; +} +Options SanitizeOptions(const std::string& dbname, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src) { + Options result = src; + result.comparator = icmp; + result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; + ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); + ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.block_size, 1<<10, 4<<20); + if (result.info_log == NULL) { + // Open a log file in the same directory as the db + src.env->CreateDir(dbname); // In case it does not exist + src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); + Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); + if (!s.ok()) { + // No place suitable for logging + result.info_log = NULL; + } + } + if (result.block_cache == NULL) { + result.block_cache = NewLRUCache(8 << 20); + } + return result; +} + +DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) + : env_(raw_options.env), + internal_comparator_(raw_options.comparator), + internal_filter_policy_(raw_options.filter_policy), + options_(SanitizeOptions(dbname, &internal_comparator_, + &internal_filter_policy_, raw_options)), + owns_info_log_(options_.info_log != raw_options.info_log), + owns_cache_(options_.block_cache != raw_options.block_cache), + dbname_(dbname), + db_lock_(NULL), + shutting_down_(NULL), + bg_cv_(&mutex_), + mem_(new MemTable(internal_comparator_)), + imm_(NULL), + logfile_(NULL), + logfile_number_(0), + log_(NULL), + seed_(0), + tmp_batch_(new WriteBatch), + bg_compaction_scheduled_(false), + manual_compaction_(NULL), + consecutive_compaction_errors_(0) { + mem_->Ref(); + has_imm_.Release_Store(NULL); + + // Reserve ten files or so for other uses and give the rest to TableCache. + const int table_cache_size = options_.max_open_files - kNumNonTableCacheFiles; + table_cache_ = new TableCache(dbname_, &options_, table_cache_size); + + versions_ = new VersionSet(dbname_, &options_, table_cache_, + &internal_comparator_); +} + +DBImpl::~DBImpl() { + // Wait for background work to finish + mutex_.Lock(); + shutting_down_.Release_Store(this); // Any non-NULL value is ok + while (bg_compaction_scheduled_) { + bg_cv_.Wait(); + } + mutex_.Unlock(); + + if (db_lock_ != NULL) { + env_->UnlockFile(db_lock_); + } + + delete versions_; + if (mem_ != NULL) mem_->Unref(); + if (imm_ != NULL) imm_->Unref(); + delete tmp_batch_; + delete log_; + delete logfile_; + delete table_cache_; + + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } +} + +Status DBImpl::NewDB() { + VersionEdit new_db; + new_db.SetComparatorName(user_comparator()->Name()); + new_db.SetLogNumber(0); + new_db.SetNextFile(2); + new_db.SetLastSequence(0); + + const std::string manifest = DescriptorFileName(dbname_, 1); + WritableFile* file; + Status s = env_->NewWritableFile(manifest, &file); + if (!s.ok()) { + return s; + } + { + log::Writer log(file); + std::string record; + new_db.EncodeTo(&record); + s = log.AddRecord(record); + if (s.ok()) { + s = file->Close(); + } + } + delete file; + if (s.ok()) { + // Make "CURRENT" file that points to the new manifest file. + s = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(manifest); + } + return s; +} + +void DBImpl::MaybeIgnoreError(Status* s) const { + if (s->ok() || options_.paranoid_checks) { + // No change needed + } else { + Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); + *s = Status::OK(); + } +} + +void DBImpl::DeleteObsoleteFiles() { + // Make a set of all of the live files + std::set live = pending_outputs_; + versions_->AddLiveFiles(&live); + + std::vector filenames; + env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + bool keep = true; + switch (type) { + case kLogFile: + keep = ((number >= versions_->LogNumber()) || + (number == versions_->PrevLogNumber())); + break; + case kDescriptorFile: + // Keep my manifest file, and any newer incarnations' + // (in case there is a race that allows other incarnations) + keep = (number >= versions_->ManifestFileNumber()); + break; + case kTableFile: + keep = (live.find(number) != live.end()); + break; + case kTempFile: + // Any temp files that are currently being written to must + // be recorded in pending_outputs_, which is inserted into "live" + keep = (live.find(number) != live.end()); + break; + case kCurrentFile: + case kDBLockFile: + case kInfoLogFile: + keep = true; + break; + } + + if (!keep) { + if (type == kTableFile) { + table_cache_->Evict(number); + } + Log(options_.info_log, "Delete type=%d #%lld\n", + int(type), + static_cast(number)); + env_->DeleteFile(dbname_ + "/" + filenames[i]); + } + } + } +} + +Status DBImpl::Recover(VersionEdit* edit) { + mutex_.AssertHeld(); + + // Ignore error from CreateDir since the creation of the DB is + // committed only when the descriptor is created, and this directory + // may already exist from a previous failed creation attempt. + env_->CreateDir(dbname_); + assert(db_lock_ == NULL); + Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); + if (!s.ok()) { + return s; + } + + if (!env_->FileExists(CurrentFileName(dbname_))) { + if (options_.create_if_missing) { + s = NewDB(); + if (!s.ok()) { + return s; + } + } else { + return Status::InvalidArgument( + dbname_, "does not exist (create_if_missing is false)"); + } + } else { + if (options_.error_if_exists) { + return Status::InvalidArgument( + dbname_, "exists (error_if_exists is true)"); + } + } + + 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 filenames; + s = env_->GetChildren(dbname_, &filenames); + if (!s.ok()) { + return s; + } + std::set expected; + versions_->AddLiveFiles(&expected); + uint64_t number; + FileType type; + std::vector 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(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]); + } + + if (s.ok()) { + if (versions_->LastSequence() < max_sequence) { + versions_->SetLastSequence(max_sequence); + } + } + } + + return s; +} + +Status DBImpl::RecoverLogFile(uint64_t log_number, + VersionEdit* edit, + SequenceNumber* max_sequence) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + const char* fname; + Status* status; // NULL if options_.paranoid_checks==false + virtual void Corruption(size_t bytes, const Status& s) { + Log(info_log, "%s%s: dropping %d bytes; %s", + (this->status == NULL ? "(ignoring error) " : ""), + fname, static_cast(bytes), s.ToString().c_str()); + if (this->status != NULL && this->status->ok()) *this->status = s; + } + }; + + mutex_.AssertHeld(); + + // Open the log file + std::string fname = LogFileName(dbname_, log_number); + SequentialFile* file; + Status status = env_->NewSequentialFile(fname, &file); + if (!status.ok()) { + MaybeIgnoreError(&status); + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.fname = fname.c_str(); + reporter.status = (options_.paranoid_checks ? &status : NULL); + // We intentially make log::Reader do checksumming even if + // paranoid_checks==false so that corruptions cause entire commits + // to be skipped instead of propagating bad information (like overly + // large sequence numbers). + log::Reader reader(file, &reporter, true/*checksum*/, + 0/*initial_offset*/); + Log(options_.info_log, "Recovering log #%llu", + (unsigned long long) log_number); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = NULL; + while (reader.ReadRecord(&record, &scratch) && + status.ok()) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + + if (mem == NULL) { + mem = new MemTable(internal_comparator_); + mem->Ref(); + } + status = WriteBatchInternal::InsertInto(&batch, mem); + MaybeIgnoreError(&status); + if (!status.ok()) { + break; + } + const SequenceNumber last_seq = + WriteBatchInternal::Sequence(&batch) + + WriteBatchInternal::Count(&batch) - 1; + if (last_seq > *max_sequence) { + *max_sequence = last_seq; + } + + if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { + status = WriteLevel0Table(mem, edit, 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. + } + + if (mem != NULL) mem->Unref(); + delete file; + return status; +} + +Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, + Version* base) { + mutex_.AssertHeld(); + const uint64_t start_micros = env_->NowMicros(); + FileMetaData meta; + meta.number = versions_->NewFileNumber(); + pending_outputs_.insert(meta.number); + Iterator* iter = mem->NewIterator(); + Log(options_.info_log, "Level-0 table #%llu: started", + (unsigned long long) meta.number); + + Status s; + { + mutex_.Unlock(); + s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + mutex_.Lock(); + } + + Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", + (unsigned long long) meta.number, + (unsigned long long) meta.file_size, + s.ToString().c_str()); + delete iter; + pending_outputs_.erase(meta.number); + + + // Note that if file_size is zero, the file has been deleted and + // should not be added to the manifest. + int level = 0; + if (s.ok() && meta.file_size > 0) { + const Slice min_user_key = meta.smallest.user_key(); + const Slice max_user_key = meta.largest.user_key(); + if (base != NULL) { + level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); + } + edit->AddFile(level, meta.number, meta.file_size, + meta.smallest, meta.largest); + } + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros; + stats.bytes_written = meta.file_size; + stats_[level].Add(stats); + return s; +} + +Status DBImpl::CompactMemTable() { + mutex_.AssertHeld(); + assert(imm_ != NULL); + + // Save the contents of the memtable as a new Table + VersionEdit edit; + Version* base = versions_->current(); + base->Ref(); + Status s = WriteLevel0Table(imm_, &edit, base); + base->Unref(); + + if (s.ok() && shutting_down_.Acquire_Load()) { + s = Status::IOError("Deleting DB during memtable compaction"); + } + + // Replace immutable memtable with the generated Table + if (s.ok()) { + edit.SetPrevLogNumber(0); + edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed + s = versions_->LogAndApply(&edit, &mutex_); + } + + if (s.ok()) { + // Commit to the new state + imm_->Unref(); + imm_ = NULL; + has_imm_.Release_Store(NULL); + DeleteObsoleteFiles(); + } + + return s; +} + +void DBImpl::CompactRange(const Slice* begin, const Slice* end) { + int max_level_with_files = 1; + { + MutexLock l(&mutex_); + Version* base = versions_->current(); + for (int level = 1; level < config::kNumLevels; level++) { + if (base->OverlapInLevel(level, begin, end)) { + max_level_with_files = level; + } + } + } + TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap + for (int level = 0; level < max_level_with_files; level++) { + TEST_CompactRange(level, begin, end); + } +} + +void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) { + assert(level >= 0); + assert(level + 1 < config::kNumLevels); + + InternalKey begin_storage, end_storage; + + ManualCompaction manual; + manual.level = level; + manual.done = false; + if (begin == NULL) { + manual.begin = NULL; + } else { + begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); + manual.begin = &begin_storage; + } + if (end == NULL) { + manual.end = NULL; + } else { + end_storage = InternalKey(*end, 0, static_cast(0)); + manual.end = &end_storage; + } + + MutexLock l(&mutex_); + while (!manual.done) { + while (manual_compaction_ != NULL) { + bg_cv_.Wait(); + } + manual_compaction_ = &manual; + MaybeScheduleCompaction(); + while (manual_compaction_ == &manual) { + bg_cv_.Wait(); + } + } +} + +Status DBImpl::TEST_CompactMemTable() { + // NULL batch means just wait for earlier writes to be done + Status s = Write(WriteOptions(), NULL); + if (s.ok()) { + // Wait until the compaction completes + MutexLock l(&mutex_); + while (imm_ != NULL && bg_error_.ok()) { + bg_cv_.Wait(); + } + if (imm_ != NULL) { + s = bg_error_; + } + } + return s; +} + +void DBImpl::MaybeScheduleCompaction() { + mutex_.AssertHeld(); + if (bg_compaction_scheduled_) { + // Already scheduled + } else if (shutting_down_.Acquire_Load()) { + // DB is being deleted; no more background compactions + } else if (imm_ == NULL && + manual_compaction_ == NULL && + !versions_->NeedsCompaction()) { + // No work to be done + } else { + bg_compaction_scheduled_ = true; + env_->Schedule(&DBImpl::BGWork, this); + } +} + +void DBImpl::BGWork(void* db) { + reinterpret_cast(db)->BackgroundCall(); +} + +void DBImpl::BackgroundCall() { + MutexLock l(&mutex_); + assert(bg_compaction_scheduled_); + if (!shutting_down_.Acquire_Load()) { + Status s = BackgroundCompaction(); + if (s.ok()) { + // Success + consecutive_compaction_errors_ = 0; + } else if (shutting_down_.Acquire_Load()) { + // Error most likely due to shutdown; do not wait + } else { + // Wait a little bit before retrying background compaction in + // case this is an environmental problem and we do not want to + // chew up resources for failed compactions for the duration of + // the problem. + bg_cv_.SignalAll(); // In case a waiter can proceed despite the error + Log(options_.info_log, "Waiting after background compaction error: %s", + s.ToString().c_str()); + mutex_.Unlock(); + ++consecutive_compaction_errors_; + int seconds_to_sleep = 1; + for (int i = 0; i < 3 && i < consecutive_compaction_errors_ - 1; ++i) { + seconds_to_sleep *= 2; + } + env_->SleepForMicroseconds(seconds_to_sleep * 1000000); + mutex_.Lock(); + } + } + + bg_compaction_scheduled_ = false; + + // Previous compaction may have produced too many files in a level, + // so reschedule another compaction if needed. + MaybeScheduleCompaction(); + bg_cv_.SignalAll(); +} + +Status DBImpl::BackgroundCompaction() { + mutex_.AssertHeld(); + + if (imm_ != NULL) { + return CompactMemTable(); + } + + Compaction* c; + bool is_manual = (manual_compaction_ != NULL); + InternalKey manual_end; + if (is_manual) { + ManualCompaction* m = manual_compaction_; + c = versions_->CompactRange(m->level, m->begin, m->end); + m->done = (c == NULL); + if (c != NULL) { + manual_end = c->input(0, c->num_input_files(0) - 1)->largest; + } + Log(options_.info_log, + "Manual compaction at level-%d from %s .. %s; will stop at %s\n", + m->level, + (m->begin ? m->begin->DebugString().c_str() : "(begin)"), + (m->end ? m->end->DebugString().c_str() : "(end)"), + (m->done ? "(end)" : manual_end.DebugString().c_str())); + } else { + c = versions_->PickCompaction(); + } + + Status status; + if (c == NULL) { + // Nothing to do + } else if (!is_manual && c->IsTrivialMove()) { + // Move file to next level + assert(c->num_input_files(0) == 1); + FileMetaData* f = c->input(0, 0); + c->edit()->DeleteFile(c->level(), f->number); + c->edit()->AddFile(c->level() + 1, f->number, f->file_size, + f->smallest, f->largest); + status = versions_->LogAndApply(c->edit(), &mutex_); + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", + static_cast(f->number), + c->level() + 1, + static_cast(f->file_size), + status.ToString().c_str(), + versions_->LevelSummary(&tmp)); + } else { + CompactionState* compact = new CompactionState(c); + status = DoCompactionWork(compact); + CleanupCompaction(compact); + c->ReleaseInputs(); + DeleteObsoleteFiles(); + } + delete c; + + if (status.ok()) { + // Done + } else if (shutting_down_.Acquire_Load()) { + // Ignore compaction errors found during shutting down + } else { + Log(options_.info_log, + "Compaction error: %s", status.ToString().c_str()); + if (options_.paranoid_checks && bg_error_.ok()) { + bg_error_ = status; + } + } + + if (is_manual) { + ManualCompaction* m = manual_compaction_; + if (!status.ok()) { + m->done = true; + } + if (!m->done) { + // We only compacted part of the requested range. Update *m + // to the range that is left to be compacted. + m->tmp_storage = manual_end; + m->begin = &m->tmp_storage; + } + manual_compaction_ = NULL; + } + return status; +} + +void DBImpl::CleanupCompaction(CompactionState* compact) { + mutex_.AssertHeld(); + if (compact->builder != NULL) { + // May happen if we get a shutdown call in the middle of compaction + compact->builder->Abandon(); + delete compact->builder; + } else { + assert(compact->outfile == NULL); + } + delete compact->outfile; + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + pending_outputs_.erase(out.number); + } + delete compact; +} + +Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { + assert(compact != NULL); + assert(compact->builder == NULL); + uint64_t file_number; + { + mutex_.Lock(); + file_number = versions_->NewFileNumber(); + pending_outputs_.insert(file_number); + CompactionState::Output out; + out.number = file_number; + out.smallest.Clear(); + out.largest.Clear(); + compact->outputs.push_back(out); + mutex_.Unlock(); + } + + // Make the output file + std::string fname = TableFileName(dbname_, file_number); + Status s = env_->NewWritableFile(fname, &compact->outfile); + if (s.ok()) { + compact->builder = new TableBuilder(options_, compact->outfile); + } + return s; +} + +Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, + Iterator* input) { + assert(compact != NULL); + assert(compact->outfile != NULL); + assert(compact->builder != NULL); + + const uint64_t output_number = compact->current_output()->number; + assert(output_number != 0); + + // Check for iterator errors + Status s = input->status(); + const uint64_t current_entries = compact->builder->NumEntries(); + if (s.ok()) { + s = compact->builder->Finish(); + } else { + compact->builder->Abandon(); + } + const uint64_t current_bytes = compact->builder->FileSize(); + compact->current_output()->file_size = current_bytes; + compact->total_bytes += current_bytes; + delete compact->builder; + compact->builder = NULL; + + // Finish and check for file errors + if (s.ok()) { + s = compact->outfile->Sync(); + } + if (s.ok()) { + s = compact->outfile->Close(); + } + delete compact->outfile; + compact->outfile = NULL; + + if (s.ok() && current_entries > 0) { + // Verify that the table is usable + Iterator* iter = table_cache_->NewIterator(ReadOptions(), + output_number, + current_bytes); + s = iter->status(); + delete iter; + if (s.ok()) { + Log(options_.info_log, + "Generated table #%llu: %lld keys, %lld bytes", + (unsigned long long) output_number, + (unsigned long long) current_entries, + (unsigned long long) current_bytes); + } + } + return s; +} + + +Status DBImpl::InstallCompactionResults(CompactionState* compact) { + mutex_.AssertHeld(); + Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1, + static_cast(compact->total_bytes)); + + // Add compaction outputs + compact->compaction->AddInputDeletions(compact->compaction->edit()); + const int level = compact->compaction->level(); + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + compact->compaction->edit()->AddFile( + level + 1, + out.number, out.file_size, out.smallest, out.largest); + } + return versions_->LogAndApply(compact->compaction->edit(), &mutex_); +} + +Status DBImpl::DoCompactionWork(CompactionState* compact) { + const uint64_t start_micros = env_->NowMicros(); + int64_t imm_micros = 0; // Micros spent doing imm_ compactions + + Log(options_.info_log, "Compacting %d@%d + %d@%d files", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1); + + assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); + assert(compact->builder == NULL); + assert(compact->outfile == NULL); + if (snapshots_.empty()) { + compact->smallest_snapshot = versions_->LastSequence(); + } else { + compact->smallest_snapshot = snapshots_.oldest()->number_; + } + + // Release mutex while we're actually doing the compaction work + mutex_.Unlock(); + + Iterator* input = versions_->MakeInputIterator(compact->compaction); + input->SeekToFirst(); + Status status; + ParsedInternalKey ikey; + std::string current_user_key; + bool has_current_user_key = false; + SequenceNumber last_sequence_for_key = kMaxSequenceNumber; + for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { + // Prioritize immutable compaction work + if (has_imm_.NoBarrier_Load() != NULL) { + const uint64_t imm_start = env_->NowMicros(); + mutex_.Lock(); + if (imm_ != NULL) { + CompactMemTable(); + bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary + } + mutex_.Unlock(); + imm_micros += (env_->NowMicros() - imm_start); + } + + Slice key = input->key(); + if (compact->compaction->ShouldStopBefore(key) && + compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + + // Handle key/value, add to state, etc. + bool drop = false; + if (!ParseInternalKey(key, &ikey)) { + // Do not hide error keys + current_user_key.clear(); + has_current_user_key = false; + last_sequence_for_key = kMaxSequenceNumber; + } else { + if (!has_current_user_key || + user_comparator()->Compare(ikey.user_key, + Slice(current_user_key)) != 0) { + // First occurrence of this user key + current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); + has_current_user_key = true; + last_sequence_for_key = kMaxSequenceNumber; + } + + if (last_sequence_for_key <= compact->smallest_snapshot) { + // Hidden by an newer entry for same user key + drop = true; // (A) + } else if (ikey.type == kTypeDeletion && + ikey.sequence <= compact->smallest_snapshot && + compact->compaction->IsBaseLevelForKey(ikey.user_key)) { + // For this user key: + // (1) there is no data in higher levels + // (2) data in lower levels will have larger sequence numbers + // (3) data in layers that are being compacted here and have + // smaller sequence numbers will be dropped in the next + // few iterations of this loop (by rule (A) above). + // Therefore this deletion marker is obsolete and can be dropped. + drop = true; + } + + last_sequence_for_key = ikey.sequence; + } +#if 0 + Log(options_.info_log, + " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " + "%d smallest_snapshot: %d", + ikey.user_key.ToString().c_str(), + (int)ikey.sequence, ikey.type, kTypeValue, drop, + compact->compaction->IsBaseLevelForKey(ikey.user_key), + (int)last_sequence_for_key, (int)compact->smallest_snapshot); +#endif + + if (!drop) { + // Open output file if necessary + if (compact->builder == NULL) { + status = OpenCompactionOutputFile(compact); + if (!status.ok()) { + break; + } + } + if (compact->builder->NumEntries() == 0) { + compact->current_output()->smallest.DecodeFrom(key); + } + compact->current_output()->largest.DecodeFrom(key); + compact->builder->Add(key, input->value()); + + // Close output file if it is big enough + if (compact->builder->FileSize() >= + compact->compaction->MaxOutputFileSize()) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + } + + input->Next(); + } + + if (status.ok() && shutting_down_.Acquire_Load()) { + status = Status::IOError("Deleting DB during compaction"); + } + if (status.ok() && compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + } + if (status.ok()) { + status = input->status(); + } + delete input; + input = NULL; + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros - imm_micros; + for (int which = 0; which < 2; which++) { + for (int i = 0; i < compact->compaction->num_input_files(which); i++) { + stats.bytes_read += compact->compaction->input(which, i)->file_size; + } + } + for (size_t i = 0; i < compact->outputs.size(); i++) { + stats.bytes_written += compact->outputs[i].file_size; + } + + mutex_.Lock(); + stats_[compact->compaction->level() + 1].Add(stats); + + if (status.ok()) { + status = InstallCompactionResults(compact); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, + "compacted to: %s", versions_->LevelSummary(&tmp)); + return status; +} + +namespace { +struct IterState { + port::Mutex* mu; + Version* version; + MemTable* mem; + MemTable* imm; +}; + +static void CleanupIteratorState(void* arg1, void* arg2) { + IterState* state = reinterpret_cast(arg1); + state->mu->Lock(); + state->mem->Unref(); + if (state->imm != NULL) state->imm->Unref(); + state->version->Unref(); + state->mu->Unlock(); + delete state; +} +} // namespace + +Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, + SequenceNumber* latest_snapshot, + uint32_t* seed) { + IterState* cleanup = new IterState; + mutex_.Lock(); + *latest_snapshot = versions_->LastSequence(); + + // Collect together all needed child iterators + std::vector list; + list.push_back(mem_->NewIterator()); + mem_->Ref(); + if (imm_ != NULL) { + list.push_back(imm_->NewIterator()); + imm_->Ref(); + } + versions_->current()->AddIterators(options, &list); + Iterator* internal_iter = + NewMergingIterator(&internal_comparator_, &list[0], list.size()); + versions_->current()->Ref(); + + cleanup->mu = &mutex_; + cleanup->mem = mem_; + cleanup->imm = imm_; + cleanup->version = versions_->current(); + internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); + + *seed = ++seed_; + mutex_.Unlock(); + return internal_iter; +} + +Iterator* DBImpl::TEST_NewInternalIterator() { + SequenceNumber ignored; + uint32_t ignored_seed; + return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed); +} + +int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { + MutexLock l(&mutex_); + return versions_->MaxNextLevelOverlappingBytes(); +} + +Status DBImpl::Get(const ReadOptions& options, + const Slice& key, + std::string* value) { + Status s; + MutexLock l(&mutex_); + SequenceNumber snapshot; + if (options.snapshot != NULL) { + snapshot = reinterpret_cast(options.snapshot)->number_; + } else { + snapshot = versions_->LastSequence(); + } + + MemTable* mem = mem_; + MemTable* imm = imm_; + Version* current = versions_->current(); + mem->Ref(); + if (imm != NULL) imm->Ref(); + current->Ref(); + + bool have_stat_update = false; + Version::GetStats stats; + + // Unlock while reading from files and memtables + { + mutex_.Unlock(); + // First look in the memtable, then in the immutable memtable (if any). + LookupKey lkey(key, snapshot); + if (mem->Get(lkey, value, &s)) { + // Done + } else if (imm != NULL && imm->Get(lkey, value, &s)) { + // Done + } else { + s = current->Get(options, lkey, value, &stats); + have_stat_update = true; + } + mutex_.Lock(); + } + + if (have_stat_update && current->UpdateStats(stats)) { + MaybeScheduleCompaction(); + } + mem->Unref(); + if (imm != NULL) imm->Unref(); + current->Unref(); + return s; +} + +Iterator* DBImpl::NewIterator(const ReadOptions& options) { + SequenceNumber latest_snapshot; + uint32_t seed; + Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed); + return NewDBIterator( + this, user_comparator(), iter, + (options.snapshot != NULL + ? reinterpret_cast(options.snapshot)->number_ + : latest_snapshot), + seed); +} + +void DBImpl::RecordReadSample(Slice key) { + MutexLock l(&mutex_); + if (versions_->current()->RecordReadSample(key)) { + MaybeScheduleCompaction(); + } +} + +const Snapshot* DBImpl::GetSnapshot() { + MutexLock l(&mutex_); + return snapshots_.New(versions_->LastSequence()); +} + +void DBImpl::ReleaseSnapshot(const Snapshot* s) { + MutexLock l(&mutex_); + snapshots_.Delete(reinterpret_cast(s)); +} + +// Convenience methods +Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { + return DB::Put(o, key, val); +} + +Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { + return DB::Delete(options, key); +} + +Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { + Writer w(&mutex_); + w.batch = my_batch; + w.sync = options.sync; + w.done = false; + + MutexLock l(&mutex_); + writers_.push_back(&w); + while (!w.done && &w != writers_.front()) { + w.cv.Wait(); + } + if (w.done) { + return w.status; + } + + // May temporarily unlock and wait. + Status status = MakeRoomForWrite(my_batch == NULL); + uint64_t last_sequence = versions_->LastSequence(); + Writer* last_writer = &w; + if (status.ok() && my_batch != NULL) { // NULL batch is for compactions + WriteBatch* updates = BuildBatchGroup(&last_writer); + WriteBatchInternal::SetSequence(updates, last_sequence + 1); + last_sequence += WriteBatchInternal::Count(updates); + + // Add to log and apply to memtable. We can release the lock + // during this phase since &w is currently responsible for logging + // and protects against concurrent loggers and concurrent writes + // into mem_. + { + mutex_.Unlock(); + status = log_->AddRecord(WriteBatchInternal::Contents(updates)); + if (status.ok() && options.sync) { + status = logfile_->Sync(); + } + if (status.ok()) { + status = WriteBatchInternal::InsertInto(updates, mem_); + } + mutex_.Lock(); + } + if (updates == tmp_batch_) tmp_batch_->Clear(); + + versions_->SetLastSequence(last_sequence); + } + + while (true) { + Writer* ready = writers_.front(); + writers_.pop_front(); + if (ready != &w) { + ready->status = status; + ready->done = true; + ready->cv.Signal(); + } + if (ready == last_writer) break; + } + + // Notify new head of write queue + if (!writers_.empty()) { + writers_.front()->cv.Signal(); + } + + return status; +} + +// REQUIRES: Writer list must be non-empty +// REQUIRES: First writer must have a non-NULL batch +WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { + assert(!writers_.empty()); + Writer* first = writers_.front(); + WriteBatch* result = first->batch; + assert(result != NULL); + + size_t size = WriteBatchInternal::ByteSize(first->batch); + + // Allow the group to grow up to a maximum size, but if the + // original write is small, limit the growth so we do not slow + // down the small write too much. + size_t max_size = 1 << 20; + if (size <= (128<<10)) { + max_size = size + (128<<10); + } + + *last_writer = first; + std::deque::iterator iter = writers_.begin(); + ++iter; // Advance past "first" + for (; iter != writers_.end(); ++iter) { + Writer* w = *iter; + if (w->sync && !first->sync) { + // Do not include a sync write into a batch handled by a non-sync write. + break; + } + + if (w->batch != NULL) { + size += WriteBatchInternal::ByteSize(w->batch); + if (size > max_size) { + // Do not make batch too big + break; + } + + // Append to *reuslt + if (result == first->batch) { + // Switch to temporary batch instead of disturbing caller's batch + result = tmp_batch_; + assert(WriteBatchInternal::Count(result) == 0); + WriteBatchInternal::Append(result, first->batch); + } + WriteBatchInternal::Append(result, w->batch); + } + *last_writer = w; + } + return result; +} + +// REQUIRES: mutex_ is held +// REQUIRES: this thread is currently at the front of the writer queue +Status DBImpl::MakeRoomForWrite(bool force) { + mutex_.AssertHeld(); + assert(!writers_.empty()); + bool allow_delay = !force; + Status s; + while (true) { + if (!bg_error_.ok()) { + // Yield previous error + s = bg_error_; + break; + } else if ( + allow_delay && + versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) { + // We are getting close to hitting a hard limit on the number of + // L0 files. Rather than delaying a single write by several + // seconds when we hit the hard limit, start delaying each + // individual write by 1ms to reduce latency variance. Also, + // this delay hands over some CPU to the compaction thread in + // case it is sharing the same core as the writer. + mutex_.Unlock(); + env_->SleepForMicroseconds(1000); + allow_delay = false; // Do not delay a single write more than once + mutex_.Lock(); + } else if (!force && + (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { + // There is room in current memtable + break; + } else if (imm_ != NULL) { + // We have filled up the current memtable, but the previous + // one is still being compacted, so we wait. + Log(options_.info_log, "Current memtable full; waiting...\n"); + bg_cv_.Wait(); + } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { + // There are too many level-0 files. + Log(options_.info_log, "Too many L0 files; waiting...\n"); + bg_cv_.Wait(); + } else { + // Attempt to switch to a new memtable and trigger compaction of old + assert(versions_->PrevLogNumber() == 0); + uint64_t new_log_number = versions_->NewFileNumber(); + WritableFile* lfile = NULL; + s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); + if (!s.ok()) { + // Avoid chewing through file number space in a tight loop. + versions_->ReuseFileNumber(new_log_number); + break; + } + delete log_; + delete logfile_; + logfile_ = lfile; + logfile_number_ = new_log_number; + log_ = new log::Writer(lfile); + imm_ = mem_; + has_imm_.Release_Store(imm_); + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + force = false; // Do not force another compaction if have room + MaybeScheduleCompaction(); + } + } + return s; +} + +bool DBImpl::GetProperty(const Slice& property, std::string* value) { + value->clear(); + + MutexLock l(&mutex_); + Slice in = property; + Slice prefix("leveldb."); + if (!in.starts_with(prefix)) return false; + in.remove_prefix(prefix.size()); + + if (in.starts_with("num-files-at-level")) { + in.remove_prefix(strlen("num-files-at-level")); + uint64_t level; + bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); + if (!ok || level >= config::kNumLevels) { + return false; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "%d", + versions_->NumLevelFiles(static_cast(level))); + *value = buf; + return true; + } + } else if (in == "stats") { + char buf[200]; + snprintf(buf, sizeof(buf), + " Compactions\n" + "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" + "--------------------------------------------------\n" + ); + value->append(buf); + for (int level = 0; level < config::kNumLevels; level++) { + int files = versions_->NumLevelFiles(level); + if (stats_[level].micros > 0 || files > 0) { + snprintf( + buf, sizeof(buf), + "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", + level, + files, + versions_->NumLevelBytes(level) / 1048576.0, + stats_[level].micros / 1e6, + stats_[level].bytes_read / 1048576.0, + stats_[level].bytes_written / 1048576.0); + value->append(buf); + } + } + return true; + } else if (in == "sstables") { + *value = versions_->current()->DebugString(); + return true; + } + + return false; +} + +void DBImpl::GetApproximateSizes( + const Range* range, int n, + uint64_t* sizes) { + // TODO(opt): better implementation + Version* v; + { + MutexLock l(&mutex_); + versions_->current()->Ref(); + v = versions_->current(); + } + + for (int i = 0; i < n; i++) { + // Convert user_key into a corresponding internal key. + InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); + uint64_t start = versions_->ApproximateOffsetOf(v, k1); + uint64_t limit = versions_->ApproximateOffsetOf(v, k2); + sizes[i] = (limit >= start ? limit - start : 0); + } + + { + MutexLock l(&mutex_); + v->Unref(); + } +} + +// Default implementations of convenience methods that subclasses of DB +// can call if they wish +Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { + WriteBatch batch; + batch.Put(key, value); + return Write(opt, &batch); +} + +Status DB::Delete(const WriteOptions& opt, const Slice& key) { + WriteBatch batch; + batch.Delete(key); + return Write(opt, &batch); +} + +DB::~DB() { } + +Status DB::Open(const Options& options, const std::string& dbname, + DB** dbptr) { + *dbptr = NULL; + + 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()) { + uint64_t new_log_number = impl->versions_->NewFileNumber(); + WritableFile* lfile; + s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), + &lfile); + if (s.ok()) { + edit.SetLogNumber(new_log_number); + 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->mutex_.Unlock(); + if (s.ok()) { + *dbptr = impl; + } else { + delete impl; + } + return s; +} + +Snapshot::~Snapshot() { +} + +Status DestroyDB(const std::string& dbname, const Options& options) { + Env* env = options.env; + std::vector filenames; + // Ignore error in case directory does not exist + env->GetChildren(dbname, &filenames); + if (filenames.empty()) { + return Status::OK(); + } + + FileLock* lock; + const std::string lockname = LockFileName(dbname); + Status result = env->LockFile(lockname, &lock); + if (result.ok()) { + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type != kDBLockFile) { // Lock file will be deleted at end + Status del = env->DeleteFile(dbname + "/" + filenames[i]); + if (result.ok() && !del.ok()) { + result = del; + } + } + } + env->UnlockFile(lock); // Ignore error since state is already gone + env->DeleteFile(lockname); + env->DeleteDir(dbname); // Ignore error in case dir contains other files + } + return result; +} + +} // namespace leveldb diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h new file mode 100644 index 0000000..75fd30a --- /dev/null +++ b/src/leveldb/db/db_impl.h @@ -0,0 +1,210 @@ +// 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_DB_IMPL_H_ +#define STORAGE_LEVELDB_DB_DB_IMPL_H_ + +#include +#include +#include "db/dbformat.h" +#include "db/log_writer.h" +#include "db/snapshot.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +class MemTable; +class TableCache; +class Version; +class VersionEdit; +class VersionSet; + +class DBImpl : public DB { + public: + DBImpl(const Options& options, const std::string& dbname); + virtual ~DBImpl(); + + // Implementations of the DB interface + virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); + virtual Status Delete(const WriteOptions&, const Slice& key); + virtual Status Write(const WriteOptions& options, WriteBatch* updates); + virtual Status Get(const ReadOptions& options, + const Slice& key, + std::string* value); + virtual Iterator* NewIterator(const ReadOptions&); + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); + virtual void CompactRange(const Slice* begin, const Slice* end); + + // Extra methods (for testing) that are not in the public DB interface + + // Compact any files in the named level that overlap [*begin,*end] + void TEST_CompactRange(int level, const Slice* begin, const Slice* end); + + // Force current memtable contents to be compacted. + Status TEST_CompactMemTable(); + + // Return an internal iterator over the current state of the database. + // The keys of this iterator are internal keys (see format.h). + // The returned iterator should be deleted when no longer needed. + Iterator* TEST_NewInternalIterator(); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t TEST_MaxNextLevelOverlappingBytes(); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. + void RecordReadSample(Slice key); + + private: + friend class DB; + struct CompactionState; + struct Writer; + + Iterator* NewInternalIterator(const ReadOptions&, + SequenceNumber* latest_snapshot, + uint32_t* seed); + + Status NewDB(); + + // 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_); + + void MaybeIgnoreError(Status* s) const; + + // Delete any unneeded files and stale in-memory entries. + void DeleteObsoleteFiles(); + + // Compact the in-memory write buffer to disk. Switches to a new + // log-file/memtable and writes a new descriptor iff successful. + Status CompactMemTable() + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status RecoverLogFile(uint64_t log_number, + VersionEdit* edit, + SequenceNumber* max_sequence) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status MakeRoomForWrite(bool force /* compact even if there is room? */) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + WriteBatch* BuildBatchGroup(Writer** last_writer); + + void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + static void BGWork(void* db); + void BackgroundCall(); + Status BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void CleanupCompaction(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Status DoCompactionWork(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status OpenCompactionOutputFile(CompactionState* compact); + Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); + Status InstallCompactionResults(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Constant after construction + Env* const env_; + const InternalKeyComparator internal_comparator_; + const InternalFilterPolicy internal_filter_policy_; + const Options options_; // options_.comparator == &internal_comparator_ + bool owns_info_log_; + bool owns_cache_; + const std::string dbname_; + + // table_cache_ provides its own synchronization + TableCache* table_cache_; + + // Lock over the persistent DB state. Non-NULL iff successfully acquired. + FileLock* db_lock_; + + // State below is protected by mutex_ + port::Mutex mutex_; + port::AtomicPointer shutting_down_; + port::CondVar bg_cv_; // Signalled when background work finishes + MemTable* mem_; + MemTable* imm_; // Memtable being compacted + port::AtomicPointer has_imm_; // So bg thread can detect non-NULL imm_ + WritableFile* logfile_; + uint64_t logfile_number_; + log::Writer* log_; + uint32_t seed_; // For sampling. + + // Queue of writers. + std::deque writers_; + WriteBatch* tmp_batch_; + + SnapshotList snapshots_; + + // Set of table files to protect from deletion because they are + // part of ongoing compactions. + std::set pending_outputs_; + + // Has a background compaction been scheduled or is running? + bool bg_compaction_scheduled_; + + // Information for a manual compaction + struct ManualCompaction { + int level; + bool done; + const InternalKey* begin; // NULL means beginning of key range + const InternalKey* end; // NULL means end of key range + InternalKey tmp_storage; // Used to keep track of compaction progress + }; + ManualCompaction* manual_compaction_; + + VersionSet* versions_; + + // Have we encountered a background error in paranoid mode? + Status bg_error_; + int consecutive_compaction_errors_; + + // Per level compaction stats. stats_[level] stores the stats for + // compactions that produced data for the specified "level". + struct CompactionStats { + int64_t micros; + int64_t bytes_read; + int64_t bytes_written; + + CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { } + + void Add(const CompactionStats& c) { + this->micros += c.micros; + this->bytes_read += c.bytes_read; + this->bytes_written += c.bytes_written; + } + }; + CompactionStats stats_[config::kNumLevels]; + + // No copying allowed + DBImpl(const DBImpl&); + void operator=(const DBImpl&); + + const Comparator* user_comparator() const { + return internal_comparator_.user_comparator(); + } +}; + +// Sanitize db options. The caller should delete result.info_log if +// it is not equal to src.info_log. +extern Options SanitizeOptions(const std::string& db, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/src/leveldb/db/db_iter.cc b/src/leveldb/db/db_iter.cc new file mode 100644 index 0000000..071a54e --- /dev/null +++ b/src/leveldb/db/db_iter.cc @@ -0,0 +1,316 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_iter.h" + +#include "db/filename.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/random.h" + +namespace leveldb { + +#if 0 +static void DumpInternalIter(Iterator* iter) { + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey k; + if (!ParseInternalKey(iter->key(), &k)) { + fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); + } else { + fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); + } + } +} +#endif + +namespace { + +// Memtables and sstables that make the DB representation contain +// (userkey,seq,type) => uservalue entries. DBIter +// combines multiple entries for the same userkey found in the DB +// representation into a single entry while accounting for sequence +// numbers, deletion markers, overwrites, etc. +class DBIter: public Iterator { + public: + // Which direction is the iterator currently moving? + // (1) When moving forward, the internal iterator is positioned at + // the exact entry that yields this->key(), this->value() + // (2) When moving backwards, the internal iterator is positioned + // just before all entries whose user key == this->key(). + enum Direction { + kForward, + kReverse + }; + + DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s, + uint32_t seed) + : db_(db), + user_comparator_(cmp), + iter_(iter), + sequence_(s), + direction_(kForward), + valid_(false), + rnd_(seed), + bytes_counter_(RandomPeriod()) { + } + virtual ~DBIter() { + delete iter_; + } + virtual bool Valid() const { return valid_; } + virtual Slice key() const { + assert(valid_); + return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; + } + virtual Slice value() const { + assert(valid_); + return (direction_ == kForward) ? iter_->value() : saved_value_; + } + virtual Status status() const { + if (status_.ok()) { + return iter_->status(); + } else { + return status_; + } + } + + virtual void Next(); + virtual void Prev(); + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + + private: + void FindNextUserEntry(bool skipping, std::string* skip); + void FindPrevUserEntry(); + bool ParseKey(ParsedInternalKey* key); + + inline void SaveKey(const Slice& k, std::string* dst) { + dst->assign(k.data(), k.size()); + } + + inline void ClearSavedValue() { + if (saved_value_.capacity() > 1048576) { + std::string empty; + swap(empty, saved_value_); + } else { + saved_value_.clear(); + } + } + + // Pick next gap with average value of config::kReadBytesPeriod. + ssize_t RandomPeriod() { + return rnd_.Uniform(2*config::kReadBytesPeriod); + } + + DBImpl* db_; + const Comparator* const user_comparator_; + Iterator* const iter_; + SequenceNumber const sequence_; + + Status status_; + std::string saved_key_; // == current key when direction_==kReverse + std::string saved_value_; // == current raw value when direction_==kReverse + Direction direction_; + bool valid_; + + Random rnd_; + ssize_t bytes_counter_; + + // No copying allowed + DBIter(const DBIter&); + void operator=(const DBIter&); +}; + +inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { + Slice k = iter_->key(); + ssize_t n = k.size() + iter_->value().size(); + bytes_counter_ -= n; + while (bytes_counter_ < 0) { + bytes_counter_ += RandomPeriod(); + db_->RecordReadSample(k); + } + if (!ParseInternalKey(k, ikey)) { + status_ = Status::Corruption("corrupted internal key in DBIter"); + return false; + } else { + return true; + } +} + +void DBIter::Next() { + assert(valid_); + + if (direction_ == kReverse) { // Switch directions? + direction_ = kForward; + // iter_ is pointing just before the entries for this->key(), + // so advance into the range of entries for this->key() and then + // use the normal skipping code below. + if (!iter_->Valid()) { + iter_->SeekToFirst(); + } else { + iter_->Next(); + } + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + return; + } + } + + // Temporarily use saved_key_ as storage for key to skip. + std::string* skip = &saved_key_; + SaveKey(ExtractUserKey(iter_->key()), skip); + FindNextUserEntry(true, skip); +} + +void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { + // Loop until we hit an acceptable entry to yield + assert(iter_->Valid()); + assert(direction_ == kForward); + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + switch (ikey.type) { + case kTypeDeletion: + // Arrange to skip all upcoming entries for this key since + // they are hidden by this deletion. + SaveKey(ikey.user_key, skip); + skipping = true; + break; + case kTypeValue: + if (skipping && + user_comparator_->Compare(ikey.user_key, *skip) <= 0) { + // Entry hidden + } else { + valid_ = true; + saved_key_.clear(); + return; + } + break; + } + } + iter_->Next(); + } while (iter_->Valid()); + saved_key_.clear(); + valid_ = false; +} + +void DBIter::Prev() { + assert(valid_); + + if (direction_ == kForward) { // Switch directions? + // iter_ is pointing at the current entry. Scan backwards until + // the key changes so we can use the normal reverse scanning code. + assert(iter_->Valid()); // Otherwise valid_ would have been false + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + while (true) { + iter_->Prev(); + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + return; + } + if (user_comparator_->Compare(ExtractUserKey(iter_->key()), + saved_key_) < 0) { + break; + } + } + direction_ = kReverse; + } + + FindPrevUserEntry(); +} + +void DBIter::FindPrevUserEntry() { + assert(direction_ == kReverse); + + ValueType value_type = kTypeDeletion; + if (iter_->Valid()) { + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + if ((value_type != kTypeDeletion) && + user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { + // We encountered a non-deleted value in entries for previous keys, + break; + } + value_type = ikey.type; + if (value_type == kTypeDeletion) { + saved_key_.clear(); + ClearSavedValue(); + } else { + Slice raw_value = iter_->value(); + if (saved_value_.capacity() > raw_value.size() + 1048576) { + std::string empty; + swap(empty, saved_value_); + } + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + saved_value_.assign(raw_value.data(), raw_value.size()); + } + } + iter_->Prev(); + } while (iter_->Valid()); + } + + if (value_type == kTypeDeletion) { + // End + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + direction_ = kForward; + } else { + valid_ = true; + } +} + +void DBIter::Seek(const Slice& target) { + direction_ = kForward; + ClearSavedValue(); + saved_key_.clear(); + AppendInternalKey( + &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek)); + iter_->Seek(saved_key_); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToFirst() { + direction_ = kForward; + ClearSavedValue(); + iter_->SeekToFirst(); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToLast() { + direction_ = kReverse; + ClearSavedValue(); + iter_->SeekToLast(); + FindPrevUserEntry(); +} + +} // anonymous namespace + +Iterator* NewDBIterator( + DBImpl* db, + const Comparator* user_key_comparator, + Iterator* internal_iter, + SequenceNumber sequence, + uint32_t seed) { + return new DBIter(db, user_key_comparator, internal_iter, sequence, seed); +} + +} // namespace leveldb diff --git a/src/leveldb/db/db_iter.h b/src/leveldb/db/db_iter.h new file mode 100644 index 0000000..04927e9 --- /dev/null +++ b/src/leveldb/db/db_iter.h @@ -0,0 +1,28 @@ +// 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_DB_ITER_H_ +#define STORAGE_LEVELDB_DB_DB_ITER_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" + +namespace leveldb { + +class DBImpl; + +// Return a new iterator that converts internal keys (yielded by +// "*internal_iter") that were live at the specified "sequence" number +// into appropriate user keys. +extern Iterator* NewDBIterator( + DBImpl* db, + const Comparator* user_key_comparator, + Iterator* internal_iter, + SequenceNumber sequence, + uint32_t seed); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc new file mode 100644 index 0000000..49aae04 --- /dev/null +++ b/src/leveldb/db/db_test.cc @@ -0,0 +1,2092 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static std::string RandomString(Random* rnd, int len) { + std::string r; + test::RandomString(rnd, len, &r); + return r; +} + +namespace { +class AtomicCounter { + private: + port::Mutex mu_; + int count_; + public: + AtomicCounter() : count_(0) { } + void Increment() { + IncrementBy(1); + } + void IncrementBy(int count) { + MutexLock l(&mu_); + count_ += count; + } + int Read() { + MutexLock l(&mu_); + return count_; + } + void Reset() { + MutexLock l(&mu_); + count_ = 0; + } +}; + +void DelayMilliseconds(int millis) { + Env::Default()->SleepForMicroseconds(millis * 1000); +} +} + +// Special Env used to delay background operations +class SpecialEnv : public EnvWrapper { + public: + // sstable Sync() calls are blocked while this pointer is non-NULL. + port::AtomicPointer delay_sstable_sync_; + + // Simulate no-space errors while this pointer is non-NULL. + port::AtomicPointer no_space_; + + // Simulate non-writable file system while this pointer is non-NULL + port::AtomicPointer non_writable_; + + // Force sync of manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_sync_error_; + + // Force write to manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_write_error_; + + bool count_random_reads_; + AtomicCounter random_read_counter_; + + AtomicCounter sleep_counter_; + AtomicCounter sleep_time_counter_; + + explicit SpecialEnv(Env* base) : EnvWrapper(base) { + delay_sstable_sync_.Release_Store(NULL); + no_space_.Release_Store(NULL); + non_writable_.Release_Store(NULL); + count_random_reads_ = false; + manifest_sync_error_.Release_Store(NULL); + manifest_write_error_.Release_Store(NULL); + } + + Status NewWritableFile(const std::string& f, WritableFile** r) { + class SSTableFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + + public: + SSTableFile(SpecialEnv* env, WritableFile* base) + : env_(env), + base_(base) { + } + ~SSTableFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->no_space_.Acquire_Load() != NULL) { + // Drop writes on the floor + return Status::OK(); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + while (env_->delay_sstable_sync_.Acquire_Load() != NULL) { + DelayMilliseconds(100); + } + return base_->Sync(); + } + }; + class ManifestFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + public: + ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { } + ~ManifestFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->manifest_write_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated writer error"); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + if (env_->manifest_sync_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated sync error"); + } else { + return base_->Sync(); + } + } + }; + + if (non_writable_.Acquire_Load() != NULL) { + return Status::IOError("simulated write error"); + } + + Status s = target()->NewWritableFile(f, r); + if (s.ok()) { + if (strstr(f.c_str(), ".sst") != NULL) { + *r = new SSTableFile(this, *r); + } else if (strstr(f.c_str(), "MANIFEST") != NULL) { + *r = new ManifestFile(this, *r); + } + } + return s; + } + + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + class CountingFile : public RandomAccessFile { + private: + RandomAccessFile* target_; + AtomicCounter* counter_; + public: + CountingFile(RandomAccessFile* target, AtomicCounter* counter) + : target_(target), counter_(counter) { + } + virtual ~CountingFile() { delete target_; } + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + counter_->Increment(); + return target_->Read(offset, n, result, scratch); + } + }; + + Status s = target()->NewRandomAccessFile(f, r); + if (s.ok() && count_random_reads_) { + *r = new CountingFile(*r, &random_read_counter_); + } + return s; + } + + virtual void SleepForMicroseconds(int micros) { + sleep_counter_.Increment(); + sleep_time_counter_.IncrementBy(micros); + } + +}; + +class DBTest { + private: + const FilterPolicy* filter_policy_; + + // Sequence of option configurations to try + enum OptionConfig { + kDefault, + kFilter, + kUncompressed, + kEnd + }; + int option_config_; + + public: + std::string dbname_; + SpecialEnv* env_; + DB* db_; + + Options last_options_; + + DBTest() : option_config_(kDefault), + env_(new SpecialEnv(Env::Default())) { + filter_policy_ = NewBloomFilterPolicy(10); + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, Options()); + db_ = NULL; + Reopen(); + } + + ~DBTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete env_; + delete filter_policy_; + } + + // Switch to a fresh database with the next option configuration to + // test. Return false if there are no more configurations to test. + bool ChangeOptions() { + option_config_++; + if (option_config_ >= kEnd) { + return false; + } else { + DestroyAndReopen(); + return true; + } + } + + // Return the current option configuration. + Options CurrentOptions() { + Options options; + switch (option_config_) { + case kFilter: + options.filter_policy = filter_policy_; + break; + case kUncompressed: + options.compression = kNoCompression; + break; + default: + break; + } + return options; + } + + DBImpl* dbfull() { + return reinterpret_cast(db_); + } + + void Reopen(Options* options = NULL) { + ASSERT_OK(TryReopen(options)); + } + + void Close() { + delete db_; + db_ = NULL; + } + + void DestroyAndReopen(Options* options = NULL) { + delete db_; + db_ = NULL; + DestroyDB(dbname_, Options()); + ASSERT_OK(TryReopen(options)); + } + + Status TryReopen(Options* options) { + delete db_; + db_ = NULL; + Options opts; + if (options != NULL) { + opts = *options; + } else { + opts = CurrentOptions(); + opts.create_if_missing = true; + } + last_options_ = opts; + + return DB::Open(opts, dbname_, &db_); + } + + Status Put(const std::string& k, const std::string& v) { + return db_->Put(WriteOptions(), k, v); + } + + Status Delete(const std::string& k) { + return db_->Delete(WriteOptions(), k); + } + + std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { + ReadOptions options; + options.snapshot = snapshot; + std::string result; + Status s = db_->Get(options, k, &result); + if (s.IsNotFound()) { + result = "NOT_FOUND"; + } else if (!s.ok()) { + result = s.ToString(); + } + return result; + } + + // Return a string that contains all key,value pairs in order, + // formatted like "(k1->v1)(k2->v2)". + std::string Contents() { + std::vector forward; + std::string result; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + std::string s = IterStatus(iter); + result.push_back('('); + result.append(s); + result.push_back(')'); + forward.push_back(s); + } + + // Check reverse iteration results are the reverse of forward results + int matched = 0; + for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { + ASSERT_LT(matched, forward.size()); + ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]); + matched++; + } + ASSERT_EQ(matched, forward.size()); + + delete iter; + return result; + } + + std::string AllEntriesFor(const Slice& user_key) { + Iterator* iter = dbfull()->TEST_NewInternalIterator(); + InternalKey target(user_key, kMaxSequenceNumber, kTypeValue); + iter->Seek(target.Encode()); + std::string result; + if (!iter->status().ok()) { + result = iter->status().ToString(); + } else { + result = "[ "; + bool first = true; + while (iter->Valid()) { + ParsedInternalKey ikey; + if (!ParseInternalKey(iter->key(), &ikey)) { + result += "CORRUPTED"; + } else { + if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) { + break; + } + if (!first) { + result += ", "; + } + first = false; + switch (ikey.type) { + case kTypeValue: + result += iter->value().ToString(); + break; + case kTypeDeletion: + result += "DEL"; + break; + } + } + iter->Next(); + } + if (!first) { + result += " "; + } + result += "]"; + } + delete iter; + return result; + } + + int NumTableFilesAtLevel(int level) { + std::string property; + ASSERT_TRUE( + db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level), + &property)); + return atoi(property.c_str()); + } + + int TotalTableFiles() { + int result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + result += NumTableFilesAtLevel(level); + } + return result; + } + + // Return spread of files per level + std::string FilesPerLevel() { + std::string result; + int last_non_zero_offset = 0; + for (int level = 0; level < config::kNumLevels; level++) { + int f = NumTableFilesAtLevel(level); + char buf[100]; + snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f); + result += buf; + if (f > 0) { + last_non_zero_offset = result.size(); + } + } + result.resize(last_non_zero_offset); + return result; + } + + int CountFiles() { + std::vector files; + env_->GetChildren(dbname_, &files); + return static_cast(files.size()); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void Compact(const Slice& start, const Slice& limit) { + db_->CompactRange(&start, &limit); + } + + // Do n memtable compactions, each of which produces an sstable + // covering the range [small,large]. + void MakeTables(int n, const std::string& small, const std::string& large) { + for (int i = 0; i < n; i++) { + Put(small, "begin"); + Put(large, "end"); + dbfull()->TEST_CompactMemTable(); + } + } + + // Prevent pushing of new sstables into deeper levels by adding + // tables that cover a specified range to all levels. + void FillLevels(const std::string& smallest, const std::string& largest) { + MakeTables(config::kNumLevels, smallest, largest); + } + + void DumpFileCounts(const char* label) { + fprintf(stderr, "---\n%s:\n", label); + fprintf(stderr, "maxoverlap: %lld\n", + static_cast( + dbfull()->TEST_MaxNextLevelOverlappingBytes())); + for (int level = 0; level < config::kNumLevels; level++) { + int num = NumTableFilesAtLevel(level); + if (num > 0) { + fprintf(stderr, " level %3d : %d files\n", level, num); + } + } + } + + std::string DumpSSTableList() { + std::string property; + db_->GetProperty("leveldb.sstables", &property); + return property; + } + + std::string IterStatus(Iterator* iter) { + std::string result; + if (iter->Valid()) { + result = iter->key().ToString() + "->" + iter->value().ToString(); + } else { + result = "(invalid)"; + } + return result; + } + + bool DeleteAnSSTFile() { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number))); + return true; + } + } + return false; + } +}; + +TEST(DBTest, Empty) { + do { + ASSERT_TRUE(db_ != NULL); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, ReadWrite) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + ASSERT_EQ("v3", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + } while (ChangeOptions()); +} + +TEST(DBTest, PutDeleteGet) { + do { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + ASSERT_OK(db_->Delete(WriteOptions(), "foo")); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromImmutableLayer) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + + env_->delay_sstable_sync_.Release_Store(env_); // Block sync calls + Put("k1", std::string(100000, 'x')); // Fill memtable + Put("k2", std::string(100000, 'y')); // Trigger compaction + ASSERT_EQ("v1", Get("foo")); + env_->delay_sstable_sync_.Release_Store(NULL); // Release sync calls + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromVersions) { + do { + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v1", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetSnapshot) { + do { + // Try with both a short key and a long key + for (int i = 0; i < 2; i++) { + std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x'); + ASSERT_OK(Put(key, "v1")); + const Snapshot* s1 = db_->GetSnapshot(); + ASSERT_OK(Put(key, "v2")); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + db_->ReleaseSnapshot(s1); + } + } while (ChangeOptions()); +} + +TEST(DBTest, GetLevel0Ordering) { + do { + // Check that we process level-0 files in correct order. The code + // below generates two level-0 files where the earlier one comes + // before the later one in the level-0 file list since the earlier + // one has a smaller "smallest" key. + ASSERT_OK(Put("bar", "b")); + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("foo", "v2")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetOrderedByLevels) { + do { + ASSERT_OK(Put("foo", "v1")); + Compact("a", "z"); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetPicksCorrectFile) { + do { + // Arrange to have multiple files in a non-level-0 level. + ASSERT_OK(Put("a", "va")); + Compact("a", "b"); + ASSERT_OK(Put("x", "vx")); + Compact("x", "y"); + ASSERT_OK(Put("f", "vf")); + Compact("f", "g"); + ASSERT_EQ("va", Get("a")); + ASSERT_EQ("vf", Get("f")); + ASSERT_EQ("vx", Get("x")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetEncountersEmptyLevel) { + do { + // Arrange for the following to happen: + // * sstable A in level 0 + // * nothing in level 1 + // * sstable B in level 2 + // Then do enough Get() calls to arrange for an automatic compaction + // of sstable A. A bug would cause the compaction to be marked as + // occuring at level 1 (instead of the correct level 0). + + // Step 1: First place sstables in levels 0 and 2 + int compaction_count = 0; + while (NumTableFilesAtLevel(0) == 0 || + NumTableFilesAtLevel(2) == 0) { + ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2"; + compaction_count++; + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + } + + // Step 2: clear level 1 if necessary. + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_EQ(NumTableFilesAtLevel(0), 1); + ASSERT_EQ(NumTableFilesAtLevel(1), 0); + ASSERT_EQ(NumTableFilesAtLevel(2), 1); + + // Step 3: read a bunch of times + for (int i = 0; i < 1000; i++) { + ASSERT_EQ("NOT_FOUND", Get("missing")); + } + + // Step 4: Wait for compaction to finish + DelayMilliseconds(1000); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } while (ChangeOptions()); +} + +TEST(DBTest, IterEmpty) { + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("foo"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSingle) { + ASSERT_OK(Put("a", "va")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMulti) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("ax"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("z"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + // Switch from reverse to forward + iter->SeekToLast(); + iter->Prev(); + iter->Prev(); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Switch from forward to reverse + iter->SeekToFirst(); + iter->Next(); + iter->Next(); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Make sure iter stays at snapshot + ASSERT_OK(Put("a", "va2")); + ASSERT_OK(Put("a2", "va3")); + ASSERT_OK(Put("b", "vb2")); + ASSERT_OK(Put("c", "vc2")); + ASSERT_OK(Delete("b")); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSmallAndLargeMix) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", std::string(100000, 'b'))); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Put("d", std::string(100000, 'd'))); + ASSERT_OK(Put("e", std::string(100000, 'e'))); + + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMultiWithDelete) { + do { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Delete("b")); + ASSERT_EQ("NOT_FOUND", Get("b")); + + Iterator* iter = db_->NewIterator(ReadOptions()); + iter->Seek("c"); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + delete iter; + } while (ChangeOptions()); +} + +TEST(DBTest, Recover) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("baz", "v5")); + + Reopen(); + ASSERT_EQ("v1", Get("foo")); + + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v5", Get("baz")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + + Reopen(); + ASSERT_EQ("v3", Get("foo")); + ASSERT_OK(Put("foo", "v4")); + ASSERT_EQ("v4", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ("v5", Get("baz")); + } while (ChangeOptions()); +} + +TEST(DBTest, RecoveryWithEmptyLog) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("foo", "v2")); + Reopen(); + Reopen(); + ASSERT_OK(Put("foo", "v3")); + Reopen(); + ASSERT_EQ("v3", Get("foo")); + } while (ChangeOptions()); +} + +// Check that writes done during a memtable compaction are recovered +// if the database is shutdown during the memtable compaction. +TEST(DBTest, RecoverDuringMemtableCompaction) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 1000000; + Reopen(&options); + + // Trigger a long memtable compaction and reopen the database during it + ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file + ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable + ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction + ASSERT_OK(Put("bar", "v2")); // Goes to new log file + + Reopen(&options); + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ(std::string(10000000, 'x'), Get("big1")); + ASSERT_EQ(std::string(1000, 'y'), Get("big2")); + } while (ChangeOptions()); +} + +static std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); +} + +TEST(DBTest, MinorCompactionsHappen) { + Options options = CurrentOptions(); + options.write_buffer_size = 10000; + Reopen(&options); + + const int N = 500; + + int starting_num_tables = TotalTableFiles(); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v'))); + } + int ending_num_tables = TotalTableFiles(); + ASSERT_GT(ending_num_tables, starting_num_tables); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } + + Reopen(); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } +} + +TEST(DBTest, RecoverWithLargeLog) { + { + Options options = CurrentOptions(); + Reopen(&options); + ASSERT_OK(Put("big1", std::string(200000, '1'))); + ASSERT_OK(Put("big2", std::string(200000, '2'))); + ASSERT_OK(Put("small3", std::string(10, '3'))); + ASSERT_OK(Put("small4", std::string(10, '4'))); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } + + // Make sure that if we re-open with a small write buffer size that + // we flush table files in the middle of a large log file. + Options options = CurrentOptions(); + options.write_buffer_size = 100000; + Reopen(&options); + ASSERT_EQ(NumTableFilesAtLevel(0), 3); + ASSERT_EQ(std::string(200000, '1'), Get("big1")); + ASSERT_EQ(std::string(200000, '2'), Get("big2")); + ASSERT_EQ(std::string(10, '3'), Get("small3")); + ASSERT_EQ(std::string(10, '4'), Get("small4")); + ASSERT_GT(NumTableFilesAtLevel(0), 1); +} + +TEST(DBTest, CompactionsGenerateMultipleFiles) { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + Reopen(&options); + + Random rnd(301); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + std::vector values; + for (int i = 0; i < 80; i++) { + values.push_back(RandomString(&rnd, 100000)); + ASSERT_OK(Put(Key(i), values[i])); + } + + // Reopening moves updates to level-0 + Reopen(&options); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 1); + for (int i = 0; i < 80; i++) { + ASSERT_EQ(Get(Key(i)), values[i]); + } +} + +TEST(DBTest, RepeatedWritesToSameKey) { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + // We must have at most one file per level except for level-0, + // which may have up to kL0_StopWritesTrigger files. + const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger; + + Random rnd(301); + std::string value = RandomString(&rnd, 2 * options.write_buffer_size); + for (int i = 0; i < 5 * kMaxFiles; i++) { + Put("key", value); + ASSERT_LE(TotalTableFiles(), kMaxFiles); + fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles()); + } +} + +TEST(DBTest, SparseMerge) { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(&options); + + FillLevels("A", "Z"); + + // Suppose there is: + // small amount of data with prefix A + // large amount of data with prefix B + // small amount of data with prefix C + // and that recent updates have made small changes to all three prefixes. + // Check that we do not do a compaction that merges all of B in one shot. + const std::string value(1000, 'x'); + Put("A", "va"); + // Write approximately 100MB of "B" values + for (int i = 0; i < 100000; i++) { + char key[100]; + snprintf(key, sizeof(key), "B%010d", i); + Put(key, value); + } + Put("C", "vc"); + dbfull()->TEST_CompactMemTable(); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + // Make sparse update + Put("A", "va2"); + Put("B100", "bvalue2"); + Put("C", "vc2"); + dbfull()->TEST_CompactMemTable(); + + // Compactions should not cause us to create a situation where + // a file overlaps too much data at the next level. + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(0, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +TEST(DBTest, ApproximateSizes) { + do { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + options.compression = kNoCompression; + DestroyAndReopen(); + + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + Reopen(&options); + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + const int N = 80; + static const int S1 = 100000; + static const int S2 = 105000; // Allow some expansion from metadata + Random rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), RandomString(&rnd, S1))); + } + + // 0 because GetApproximateSizes() does not account for memtable space + ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + for (int compact_start = 0; compact_start < N; compact_start += 10) { + for (int i = 0; i < N; i += 10) { + ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i)); + ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1))); + ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10)); + } + ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50)); + ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50)); + + std::string cstart_str = Key(compact_start); + std::string cend_str = Key(compact_start + 9); + Slice cstart = cstart_str; + Slice cend = cend_str; + dbfull()->TEST_CompactRange(0, &cstart, &cend); + } + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 0); + } + } while (ChangeOptions()); +} + +TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { + do { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(); + + Random rnd(301); + std::string big1 = RandomString(&rnd, 100000); + ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(2), big1)); + ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(4), big1)); + ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); + ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + ASSERT_TRUE(Between(Size("", Key(0)), 0, 0)); + ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000)); + ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000)); + ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000)); + ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000)); + ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000)); + ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000)); + ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000)); + ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000)); + + ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000)); + + dbfull()->TEST_CompactRange(0, NULL, NULL); + } + } while (ChangeOptions()); +} + +TEST(DBTest, IteratorPinsRef) { + Put("foo", "hello"); + + // Get iterator that will yield the current contents of the DB. + Iterator* iter = db_->NewIterator(ReadOptions()); + + // Write to force compactions + Put("foo", "newvalue1"); + for (int i = 0; i < 100; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values + } + Put("foo", "newvalue2"); + + iter->SeekToFirst(); + ASSERT_TRUE(iter->Valid()); + ASSERT_EQ("foo", iter->key().ToString()); + ASSERT_EQ("hello", iter->value().ToString()); + iter->Next(); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +TEST(DBTest, Snapshot) { + do { + Put("foo", "v1"); + const Snapshot* s1 = db_->GetSnapshot(); + Put("foo", "v2"); + const Snapshot* s2 = db_->GetSnapshot(); + Put("foo", "v3"); + const Snapshot* s3 = db_->GetSnapshot(); + + Put("foo", "v4"); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v3", Get("foo", s3)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s3); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s1); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s2); + ASSERT_EQ("v4", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, HiddenValuesAreRemoved) { + do { + Random rnd(301); + FillLevels("a", "z"); + + std::string big = RandomString(&rnd, 50000); + Put("foo", big); + Put("pastfoo", "v"); + const Snapshot* snapshot = db_->GetSnapshot(); + Put("foo", "tiny"); + Put("pastfoo2", "v2"); // Advance sequence number one more + + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + ASSERT_GT(NumTableFilesAtLevel(0), 0); + + ASSERT_EQ(big, Get("foo", snapshot)); + ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000)); + db_->ReleaseSnapshot(snapshot); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]"); + Slice x("x"); + dbfull()->TEST_CompactRange(0, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GE(NumTableFilesAtLevel(1), 1); + dbfull()->TEST_CompactRange(1, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + + ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000)); + } while (ChangeOptions()); +} + +TEST(DBTest, DeletionMarkers1) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + Put("foo", "v2"); + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + Slice z("z"); + dbfull()->TEST_CompactRange(last-2, NULL, &z); + // DEL eliminated, but v1 remains because we aren't compacting that level + // (DEL can be eliminated because v2 hides v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]"); +} + +TEST(DBTest, DeletionMarkers2) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-2, NULL, NULL); + // DEL kept: "last" file overlaps + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ ]"); +} + +TEST(DBTest, OverlapInLevel0) { + do { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config"; + + // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. + ASSERT_OK(Put("100", "v100")); + ASSERT_OK(Put("999", "v999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Delete("100")); + ASSERT_OK(Delete("999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("0,1,1", FilesPerLevel()); + + // Make files spanning the following ranges in level-0: + // files[0] 200 .. 900 + // files[1] 300 .. 500 + // Note that files are sorted by smallest key. + ASSERT_OK(Put("300", "v300")); + ASSERT_OK(Put("500", "v500")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("200", "v200")); + ASSERT_OK(Put("600", "v600")); + ASSERT_OK(Put("900", "v900")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("2,1,1", FilesPerLevel()); + + // Compact away the placeholder files we created initially + dbfull()->TEST_CompactRange(1, NULL, NULL); + dbfull()->TEST_CompactRange(2, NULL, NULL); + ASSERT_EQ("2", FilesPerLevel()); + + // Do a memtable compaction. Before bug-fix, the compaction would + // not detect the overlap with level-0 files and would incorrectly place + // the deletion in a deeper level. + ASSERT_OK(Delete("600")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("3", FilesPerLevel()); + ASSERT_EQ("NOT_FOUND", Get("600")); + } while (ChangeOptions()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_a) { + Reopen(); + ASSERT_OK(Put("b", "v")); + Reopen(); + ASSERT_OK(Delete("b")); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Put("a", "v")); + Reopen(); + Reopen(); + ASSERT_EQ("(a->v)", Contents()); + DelayMilliseconds(1000); // Wait for compaction to finish + ASSERT_EQ("(a->v)", Contents()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_b) { + Reopen(); + Put("",""); + Reopen(); + Delete("e"); + Put("",""); + Reopen(); + Put("c", "cv"); + Reopen(); + Put("",""); + Reopen(); + Put("",""); + DelayMilliseconds(1000); // Wait for compaction to finish + Reopen(); + Put("d","dv"); + Reopen(); + Put("",""); + Reopen(); + Delete("d"); + Delete("b"); + Reopen(); + ASSERT_EQ("(->)(c->cv)", Contents()); + DelayMilliseconds(1000); // Wait for compaction to finish + ASSERT_EQ("(->)(c->cv)", Contents()); +} + +TEST(DBTest, ComparatorCheck) { + class NewComparator : public Comparator { + public: + virtual const char* Name() const { return "leveldb.NewComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(a, b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + BytewiseComparator()->FindShortestSeparator(s, l); + } + virtual void FindShortSuccessor(std::string* key) const { + BytewiseComparator()->FindShortSuccessor(key); + } + }; + NewComparator cmp; + Options new_options = CurrentOptions(); + new_options.comparator = &cmp; + Status s = TryReopen(&new_options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, CustomComparator) { + class NumberComparator : public Comparator { + public: + virtual const char* Name() const { return "test.NumberComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return ToNumber(a) - ToNumber(b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + ToNumber(*s); // Check format + ToNumber(l); // Check format + } + virtual void FindShortSuccessor(std::string* key) const { + ToNumber(*key); // Check format + } + private: + static int ToNumber(const Slice& x) { + // Check that there are no extra characters. + ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']') + << EscapeString(x); + int val; + char ignored; + ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1) + << EscapeString(x); + return val; + } + }; + NumberComparator cmp; + Options new_options = CurrentOptions(); + new_options.create_if_missing = true; + new_options.comparator = &cmp; + new_options.filter_policy = NULL; // Cannot use bloom filters + new_options.write_buffer_size = 1000; // Compact more often + DestroyAndReopen(&new_options); + ASSERT_OK(Put("[10]", "ten")); + ASSERT_OK(Put("[0x14]", "twenty")); + for (int i = 0; i < 2; i++) { + ASSERT_EQ("ten", Get("[10]")); + ASSERT_EQ("ten", Get("[0xa]")); + ASSERT_EQ("twenty", Get("[20]")); + ASSERT_EQ("twenty", Get("[0x14]")); + ASSERT_EQ("NOT_FOUND", Get("[15]")); + ASSERT_EQ("NOT_FOUND", Get("[0xf]")); + Compact("[0]", "[9999]"); + } + + for (int run = 0; run < 2; run++) { + for (int i = 0; i < 1000; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "[%d]", i*10); + ASSERT_OK(Put(buf, buf)); + } + Compact("[0]", "[1000000]"); + } +} + +TEST(DBTest, ManualCompaction) { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) + << "Need to update this test to match kMaxMemCompactLevel"; + + MakeTables(3, "p", "q"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls before files + Compact("", "c"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls after files + Compact("r", "z"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range overlaps files + Compact("p1", "p9"); + ASSERT_EQ("0,0,1", FilesPerLevel()); + + // Populate a different range + MakeTables(3, "c", "e"); + ASSERT_EQ("1,1,2", FilesPerLevel()); + + // Compact just the new range + Compact("b", "f"); + ASSERT_EQ("0,0,2", FilesPerLevel()); + + // Compact all + MakeTables(1, "a", "z"); + ASSERT_EQ("0,1,2", FilesPerLevel()); + db_->CompactRange(NULL, NULL); + ASSERT_EQ("0,0,1", FilesPerLevel()); +} + +TEST(DBTest, DBOpen_Options) { + std::string dbname = test::TmpDir() + "/db_options_test"; + DestroyDB(dbname, Options()); + + // Does not exist, and create_if_missing == false: error + DB* db = NULL; + Options opts; + opts.create_if_missing = false; + Status s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL); + ASSERT_TRUE(db == NULL); + + // Does not exist, and create_if_missing == true: OK + opts.create_if_missing = true; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + // Does exist, and error_if_exists == true: error + opts.create_if_missing = false; + opts.error_if_exists = true; + s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL); + ASSERT_TRUE(db == NULL); + + // Does exist, and error_if_exists == false: OK + opts.create_if_missing = true; + opts.error_if_exists = false; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; +} + +TEST(DBTest, Locking) { + DB* db2 = NULL; + Status s = DB::Open(CurrentOptions(), dbname_, &db2); + ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db"; +} + +// Check that number of files does not grow when we are out of space +TEST(DBTest, NoSpace) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + const int num_files = CountFiles(); + env_->no_space_.Release_Store(env_); // Force out-of-space errors + env_->sleep_counter_.Reset(); + for (int i = 0; i < 5; i++) { + for (int level = 0; level < config::kNumLevels-1; level++) { + dbfull()->TEST_CompactRange(level, NULL, NULL); + } + } + env_->no_space_.Release_Store(NULL); + ASSERT_LT(CountFiles(), num_files + 3); + + // Check that compaction attempts slept after errors + ASSERT_GE(env_->sleep_counter_.Read(), 5); +} + +TEST(DBTest, ExponentialBackoff) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + env_->non_writable_.Release_Store(env_); // Force errors for new files + env_->sleep_counter_.Reset(); + env_->sleep_time_counter_.Reset(); + for (int i = 0; i < 5; i++) { + dbfull()->TEST_CompactRange(2, NULL, NULL); + } + env_->non_writable_.Release_Store(NULL); + + // Wait for compaction to finish + DelayMilliseconds(1000); + + ASSERT_GE(env_->sleep_counter_.Read(), 5); + ASSERT_LT(env_->sleep_counter_.Read(), 10); + ASSERT_GE(env_->sleep_time_counter_.Read(), 10e6); +} + +TEST(DBTest, NonWritableFileSystem) { + Options options = CurrentOptions(); + options.write_buffer_size = 1000; + options.env = env_; + Reopen(&options); + ASSERT_OK(Put("foo", "v1")); + env_->non_writable_.Release_Store(env_); // Force errors for new files + std::string big(100000, 'x'); + int errors = 0; + for (int i = 0; i < 20; i++) { + fprintf(stderr, "iter %d; errors %d\n", i, errors); + if (!Put("foo", big).ok()) { + errors++; + DelayMilliseconds(100); + } + } + ASSERT_GT(errors, 0); + env_->non_writable_.Release_Store(NULL); +} + +TEST(DBTest, ManifestWriteError) { + // Test for the following problem: + // (a) Compaction produces file F + // (b) Log record containing F is written to MANIFEST file, but Sync() fails + // (c) GC deletes F + // (d) After reopening DB, reads fail since deleted F is named in log record + + // We iterate twice. In the second iteration, everything is the + // same except the log record never makes it to the MANIFEST file. + for (int iter = 0; iter < 2; iter++) { + port::AtomicPointer* error_type = (iter == 0) + ? &env_->manifest_sync_error_ + : &env_->manifest_write_error_; + + // Insert foo=>bar mapping + Options options = CurrentOptions(); + options.env = env_; + options.create_if_missing = true; + options.error_if_exists = false; + DestroyAndReopen(&options); + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Memtable compaction (will succeed) + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level + + // Merging compaction (will fail) + error_type->Release_Store(env_); + dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail + ASSERT_EQ("bar", Get("foo")); + + // Recovery: should not lose data + error_type->Release_Store(NULL); + Reopen(&options); + ASSERT_EQ("bar", Get("foo")); + } +} + +TEST(DBTest, MissingSSTFile) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + + Close(); + ASSERT_TRUE(DeleteAnSSTFile()); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, FilesDeletedAfterCompaction) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + const int num_files = CountFiles(); + for (int i = 0; i < 10; i++) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + } + ASSERT_EQ(CountFiles(), num_files); +} + +TEST(DBTest, BloomFilter) { + env_->count_random_reads_ = true; + Options options = CurrentOptions(); + options.env = env_; + options.block_cache = NewLRUCache(0); // Prevent cache hits + options.filter_policy = NewBloomFilterPolicy(10); + Reopen(&options); + + // Populate multiple layers + const int N = 10000; + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i))); + } + Compact("a", "z"); + for (int i = 0; i < N; i += 100) { + ASSERT_OK(Put(Key(i), Key(i))); + } + dbfull()->TEST_CompactMemTable(); + + // Prevent auto compactions triggered by seeks + env_->delay_sstable_sync_.Release_Store(env_); + + // Lookup present keys. Should rarely read from small sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i), Get(Key(i))); + } + int reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d present => %d reads\n", N, reads); + ASSERT_GE(reads, N); + ASSERT_LE(reads, N + 2*N/100); + + // Lookup present keys. Should rarely read from either sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing")); + } + reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d missing => %d reads\n", N, reads); + ASSERT_LE(reads, 3*N/100); + + env_->delay_sstable_sync_.Release_Store(NULL); + Close(); + delete options.block_cache; + delete options.filter_policy; +} + +// Multi-threaded test: +namespace { + +static const int kNumThreads = 4; +static const int kTestSeconds = 10; +static const int kNumKeys = 1000; + +struct MTState { + DBTest* test; + port::AtomicPointer stop; + port::AtomicPointer counter[kNumThreads]; + port::AtomicPointer thread_done[kNumThreads]; +}; + +struct MTThread { + MTState* state; + int id; +}; + +static void MTThreadBody(void* arg) { + MTThread* t = reinterpret_cast(arg); + int id = t->id; + DB* db = t->state->test->db_; + uintptr_t counter = 0; + fprintf(stderr, "... starting thread %d\n", id); + Random rnd(1000 + id); + std::string value; + char valbuf[1500]; + while (t->state->stop.Acquire_Load() == NULL) { + t->state->counter[id].Release_Store(reinterpret_cast(counter)); + + int key = rnd.Uniform(kNumKeys); + char keybuf[20]; + snprintf(keybuf, sizeof(keybuf), "%016d", key); + + if (rnd.OneIn(2)) { + // Write values of the form . + // We add some padding for force compactions. + snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", + key, id, static_cast(counter)); + ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf))); + } else { + // Read a value and verify that it matches the pattern written above. + Status s = db->Get(ReadOptions(), Slice(keybuf), &value); + if (s.IsNotFound()) { + // Key has not yet been written + } else { + // Check that the writer thread counter is >= the counter in the value + ASSERT_OK(s); + int k, w, c; + ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value; + ASSERT_EQ(k, key); + ASSERT_GE(w, 0); + ASSERT_LT(w, kNumThreads); + ASSERT_LE(c, reinterpret_cast( + t->state->counter[w].Acquire_Load())); + } + } + counter++; + } + t->state->thread_done[id].Release_Store(t); + fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter)); +} + +} // namespace + +TEST(DBTest, MultiThreaded) { + do { + // Initialize state + MTState mt; + mt.test = this; + mt.stop.Release_Store(0); + for (int id = 0; id < kNumThreads; id++) { + mt.counter[id].Release_Store(0); + mt.thread_done[id].Release_Store(0); + } + + // Start threads + MTThread thread[kNumThreads]; + for (int id = 0; id < kNumThreads; id++) { + thread[id].state = &mt; + thread[id].id = id; + env_->StartThread(MTThreadBody, &thread[id]); + } + + // Let them run for a while + DelayMilliseconds(kTestSeconds * 1000); + + // Stop the threads and wait for them to finish + mt.stop.Release_Store(&mt); + for (int id = 0; id < kNumThreads; id++) { + while (mt.thread_done[id].Acquire_Load() == NULL) { + DelayMilliseconds(100); + } + } + } while (ChangeOptions()); +} + +namespace { +typedef std::map KVMap; +} + +class ModelDB: public DB { + public: + class ModelSnapshot : public Snapshot { + public: + KVMap map_; + }; + + explicit ModelDB(const Options& options): options_(options) { } + ~ModelDB() { } + virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { + return DB::Put(o, k, v); + } + virtual Status Delete(const WriteOptions& o, const Slice& key) { + return DB::Delete(o, key); + } + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) { + assert(false); // Not implemented + return Status::NotFound(key); + } + virtual Iterator* NewIterator(const ReadOptions& options) { + if (options.snapshot == NULL) { + KVMap* saved = new KVMap; + *saved = map_; + return new ModelIter(saved, true); + } else { + const KVMap* snapshot_state = + &(reinterpret_cast(options.snapshot)->map_); + return new ModelIter(snapshot_state, false); + } + } + virtual const Snapshot* GetSnapshot() { + ModelSnapshot* snapshot = new ModelSnapshot; + snapshot->map_ = map_; + return snapshot; + } + + virtual void ReleaseSnapshot(const Snapshot* snapshot) { + delete reinterpret_cast(snapshot); + } + virtual Status Write(const WriteOptions& options, WriteBatch* batch) { + class Handler : public WriteBatch::Handler { + public: + KVMap* map_; + virtual void Put(const Slice& key, const Slice& value) { + (*map_)[key.ToString()] = value.ToString(); + } + virtual void Delete(const Slice& key) { + map_->erase(key.ToString()); + } + }; + Handler handler; + handler.map_ = &map_; + return batch->Iterate(&handler); + } + + virtual bool GetProperty(const Slice& property, std::string* value) { + return false; + } + virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) { + for (int i = 0; i < n; i++) { + sizes[i] = 0; + } + } + virtual void CompactRange(const Slice* start, const Slice* end) { + } + + private: + class ModelIter: public Iterator { + public: + ModelIter(const KVMap* map, bool owned) + : map_(map), owned_(owned), iter_(map_->end()) { + } + ~ModelIter() { + if (owned_) delete map_; + } + virtual bool Valid() const { return iter_ != map_->end(); } + virtual void SeekToFirst() { iter_ = map_->begin(); } + virtual void SeekToLast() { + if (map_->empty()) { + iter_ = map_->end(); + } else { + iter_ = map_->find(map_->rbegin()->first); + } + } + virtual void Seek(const Slice& k) { + iter_ = map_->lower_bound(k.ToString()); + } + virtual void Next() { ++iter_; } + virtual void Prev() { --iter_; } + virtual Slice key() const { return iter_->first; } + virtual Slice value() const { return iter_->second; } + virtual Status status() const { return Status::OK(); } + private: + const KVMap* const map_; + const bool owned_; // Do we own map_ + KVMap::const_iterator iter_; + }; + const Options options_; + KVMap map_; +}; + +static std::string RandomKey(Random* rnd) { + int len = (rnd->OneIn(3) + ? 1 // Short sometimes to encourage collisions + : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10))); + return test::RandomKey(rnd, len); +} + +static bool CompareIterators(int step, + DB* model, + DB* db, + const Snapshot* model_snap, + const Snapshot* db_snap) { + ReadOptions options; + options.snapshot = model_snap; + Iterator* miter = model->NewIterator(options); + options.snapshot = db_snap; + Iterator* dbiter = db->NewIterator(options); + bool ok = true; + int count = 0; + for (miter->SeekToFirst(), dbiter->SeekToFirst(); + ok && miter->Valid() && dbiter->Valid(); + miter->Next(), dbiter->Next()) { + count++; + if (miter->key().compare(dbiter->key()) != 0) { + fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(dbiter->key()).c_str()); + ok = false; + break; + } + + if (miter->value().compare(dbiter->value()) != 0) { + fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(miter->value()).c_str(), + EscapeString(miter->value()).c_str()); + ok = false; + } + } + + if (ok) { + if (miter->Valid() != dbiter->Valid()) { + fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n", + step, miter->Valid(), dbiter->Valid()); + ok = false; + } + } + fprintf(stderr, "%d entries compared: ok=%d\n", count, ok); + delete miter; + delete dbiter; + return ok; +} + +TEST(DBTest, Randomized) { + Random rnd(test::RandomSeed()); + do { + ModelDB model(CurrentOptions()); + const int N = 10000; + const Snapshot* model_snap = NULL; + const Snapshot* db_snap = NULL; + std::string k, v; + for (int step = 0; step < N; step++) { + if (step % 100 == 0) { + fprintf(stderr, "Step %d of %d\n", step, N); + } + // TODO(sanjay): Test Get() works + int p = rnd.Uniform(100); + if (p < 45) { // Put + k = RandomKey(&rnd); + v = RandomString(&rnd, + rnd.OneIn(20) + ? 100 + rnd.Uniform(100) + : rnd.Uniform(8)); + ASSERT_OK(model.Put(WriteOptions(), k, v)); + ASSERT_OK(db_->Put(WriteOptions(), k, v)); + + } else if (p < 90) { // Delete + k = RandomKey(&rnd); + ASSERT_OK(model.Delete(WriteOptions(), k)); + ASSERT_OK(db_->Delete(WriteOptions(), k)); + + + } else { // Multi-element batch + WriteBatch b; + const int num = rnd.Uniform(8); + for (int i = 0; i < num; i++) { + if (i == 0 || !rnd.OneIn(10)) { + k = RandomKey(&rnd); + } else { + // Periodically re-use the same key from the previous iter, so + // we have multiple entries in the write batch for the same key + } + if (rnd.OneIn(2)) { + v = RandomString(&rnd, rnd.Uniform(10)); + b.Put(k, v); + } else { + b.Delete(k); + } + } + ASSERT_OK(model.Write(WriteOptions(), &b)); + ASSERT_OK(db_->Write(WriteOptions(), &b)); + } + + if ((step % 100) == 0) { + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap)); + // Save a snapshot from each DB this time that we'll use next + // time we compare things, to make sure the current state is + // preserved with the snapshot + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + + Reopen(); + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + + model_snap = model.GetSnapshot(); + db_snap = db_->GetSnapshot(); + } + } + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + } while (ChangeOptions()); +} + +std::string MakeKey(unsigned int num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%016u", num); + return std::string(buf); +} + +void BM_LogAndApply(int iters, int num_base_files) { + std::string dbname = test::TmpDir() + "/leveldb_test_benchmark"; + DestroyDB(dbname, Options()); + + DB* db = NULL; + Options opts; + opts.create_if_missing = true; + Status s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + Env* env = Env::Default(); + + port::Mutex mu; + MutexLock l(&mu); + + InternalKeyComparator cmp(BytewiseComparator()); + Options options; + VersionSet vset(dbname, &options, NULL, &cmp); + ASSERT_OK(vset.Recover()); + VersionEdit vbase; + uint64_t fnum = 1; + for (int i = 0; i < num_base_files; i++) { + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vbase.AddFile(2, fnum++, 1 /* file size */, start, limit); + } + ASSERT_OK(vset.LogAndApply(&vbase, &mu)); + + uint64_t start_micros = env->NowMicros(); + + for (int i = 0; i < iters; i++) { + VersionEdit vedit; + vedit.DeleteFile(2, fnum); + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vedit.AddFile(2, fnum++, 1 /* file size */, start, limit); + vset.LogAndApply(&vedit, &mu); + } + uint64_t stop_micros = env->NowMicros(); + unsigned int us = stop_micros - start_micros; + char buf[16]; + snprintf(buf, sizeof(buf), "%d", num_base_files); + fprintf(stderr, + "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", + buf, iters, us, ((float)us) / iters); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + if (argc > 1 && std::string(argv[1]) == "--benchmark") { + leveldb::BM_LogAndApply(1000, 1); + leveldb::BM_LogAndApply(1000, 100); + leveldb::BM_LogAndApply(1000, 10000); + leveldb::BM_LogAndApply(100, 100000); + return 0; + } + + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/dbformat.cc b/src/leveldb/db/dbformat.cc new file mode 100644 index 0000000..20a7ca4 --- /dev/null +++ b/src/leveldb/db/dbformat.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { + +static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { + assert(seq <= kMaxSequenceNumber); + assert(t <= kValueTypeForSeek); + return (seq << 8) | t; +} + +void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { + result->append(key.user_key.data(), key.user_key.size()); + PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); +} + +std::string ParsedInternalKey::DebugString() const { + char buf[50]; + snprintf(buf, sizeof(buf), "' @ %llu : %d", + (unsigned long long) sequence, + int(type)); + std::string result = "'"; + result += EscapeString(user_key.ToString()); + result += buf; + return result; +} + +std::string InternalKey::DebugString() const { + std::string result; + ParsedInternalKey parsed; + if (ParseInternalKey(rep_, &parsed)) { + result = parsed.DebugString(); + } else { + result = "(bad)"; + result.append(EscapeString(rep_)); + } + return result; +} + +const char* InternalKeyComparator::Name() const { + return "leveldb.InternalKeyComparator"; +} + +int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { + // Order by: + // increasing user key (according to user-supplied comparator) + // decreasing sequence number + // decreasing type (though sequence# should be enough to disambiguate) + int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); + if (r == 0) { + const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); + const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); + if (anum > bnum) { + r = -1; + } else if (anum < bnum) { + r = +1; + } + } + return r; +} + +void InternalKeyComparator::FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Attempt to shorten the user portion of the key + Slice user_start = ExtractUserKey(*start); + Slice user_limit = ExtractUserKey(limit); + std::string tmp(user_start.data(), user_start.size()); + user_comparator_->FindShortestSeparator(&tmp, user_limit); + if (tmp.size() < user_start.size() && + user_comparator_->Compare(user_start, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*start, tmp) < 0); + assert(this->Compare(tmp, limit) < 0); + start->swap(tmp); + } +} + +void InternalKeyComparator::FindShortSuccessor(std::string* key) const { + Slice user_key = ExtractUserKey(*key); + std::string tmp(user_key.data(), user_key.size()); + user_comparator_->FindShortSuccessor(&tmp); + if (tmp.size() < user_key.size() && + user_comparator_->Compare(user_key, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*key, tmp) < 0); + key->swap(tmp); + } +} + +const char* InternalFilterPolicy::Name() const { + return user_policy_->Name(); +} + +void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, + std::string* dst) const { + // We rely on the fact that the code in table.cc does not mind us + // adjusting keys[]. + Slice* mkey = const_cast(keys); + for (int i = 0; i < n; i++) { + mkey[i] = ExtractUserKey(keys[i]); + // TODO(sanjay): Suppress dups? + } + user_policy_->CreateFilter(keys, n, dst); +} + +bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { + return user_policy_->KeyMayMatch(ExtractUserKey(key), f); +} + +LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { + size_t usize = user_key.size(); + size_t needed = usize + 13; // A conservative estimate + char* dst; + if (needed <= sizeof(space_)) { + dst = space_; + } else { + dst = new char[needed]; + } + start_ = dst; + dst = EncodeVarint32(dst, usize + 8); + kstart_ = dst; + memcpy(dst, user_key.data(), usize); + dst += usize; + EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); + dst += 8; + end_ = dst; +} + +} // namespace leveldb diff --git a/src/leveldb/db/dbformat.h b/src/leveldb/db/dbformat.h new file mode 100644 index 0000000..5d8a032 --- /dev/null +++ b/src/leveldb/db/dbformat.h @@ -0,0 +1,230 @@ +// 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_FORMAT_H_ +#define STORAGE_LEVELDB_DB_FORMAT_H_ + +#include +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "leveldb/slice.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +// Grouping of constants. We may want to make some of these +// parameters set via options. +namespace config { +static const int kNumLevels = 7; + +// Level-0 compaction is started when we hit this many files. +static const int kL0_CompactionTrigger = 4; + +// Soft limit on number of level-0 files. We slow down writes at this point. +static const int kL0_SlowdownWritesTrigger = 8; + +// Maximum number of level-0 files. We stop writes at this point. +static const int kL0_StopWritesTrigger = 12; + +// Maximum level to which a new compacted memtable is pushed if it +// does not create overlap. We try to push to level 2 to avoid the +// relatively expensive level 0=>1 compactions and to avoid some +// expensive manifest file operations. We do not push all the way to +// the largest level since that can generate a lot of wasted disk +// space if the same key space is being repeatedly overwritten. +static const int kMaxMemCompactLevel = 2; + +// Approximate gap in bytes between samples of data read during iteration. +static const int kReadBytesPeriod = 1048576; + +} // namespace config + +class InternalKey; + +// Value types encoded as the last component of internal keys. +// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk +// data structures. +enum ValueType { + kTypeDeletion = 0x0, + kTypeValue = 0x1 +}; +// kValueTypeForSeek defines the ValueType that should be passed when +// constructing a ParsedInternalKey object for seeking to a particular +// sequence number (since we sort sequence numbers in decreasing order +// and the value type is embedded as the low 8 bits in the sequence +// number in internal keys, we need to use the highest-numbered +// ValueType, not the lowest). +static const ValueType kValueTypeForSeek = kTypeValue; + +typedef uint64_t SequenceNumber; + +// We leave eight bits empty at the bottom so a type and sequence# +// can be packed together into 64-bits. +static const SequenceNumber kMaxSequenceNumber = + ((0x1ull << 56) - 1); + +struct ParsedInternalKey { + Slice user_key; + SequenceNumber sequence; + ValueType type; + + ParsedInternalKey() { } // Intentionally left uninitialized (for speed) + ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) + : user_key(u), sequence(seq), type(t) { } + std::string DebugString() const; +}; + +// Return the length of the encoding of "key". +inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { + return key.user_key.size() + 8; +} + +// Append the serialization of "key" to *result. +extern void AppendInternalKey(std::string* result, + const ParsedInternalKey& key); + +// Attempt to parse an internal key from "internal_key". On success, +// stores the parsed data in "*result", and returns true. +// +// On error, returns false, leaves "*result" in an undefined state. +extern bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result); + +// Returns the user key portion of an internal key. +inline Slice ExtractUserKey(const Slice& internal_key) { + assert(internal_key.size() >= 8); + return Slice(internal_key.data(), internal_key.size() - 8); +} + +inline ValueType ExtractValueType(const Slice& internal_key) { + assert(internal_key.size() >= 8); + const size_t n = internal_key.size(); + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + return static_cast(c); +} + +// A comparator for internal keys that uses a specified comparator for +// the user key portion and breaks ties by decreasing sequence number. +class InternalKeyComparator : public Comparator { + private: + const Comparator* user_comparator_; + public: + explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { } + virtual const char* Name() const; + virtual int Compare(const Slice& a, const Slice& b) const; + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const; + virtual void FindShortSuccessor(std::string* key) const; + + const Comparator* user_comparator() const { return user_comparator_; } + + int Compare(const InternalKey& a, const InternalKey& b) const; +}; + +// Filter policy wrapper that converts from internal keys to user keys +class InternalFilterPolicy : public FilterPolicy { + private: + const FilterPolicy* const user_policy_; + public: + explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { } + virtual const char* Name() const; + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; +}; + +// Modules in this directory should keep internal keys wrapped inside +// the following class instead of plain strings so that we do not +// incorrectly use string comparisons instead of an InternalKeyComparator. +class InternalKey { + private: + std::string rep_; + public: + InternalKey() { } // Leave rep_ as empty to indicate it is invalid + InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { + AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); + } + + void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } + Slice Encode() const { + assert(!rep_.empty()); + return rep_; + } + + Slice user_key() const { return ExtractUserKey(rep_); } + + void SetFrom(const ParsedInternalKey& p) { + rep_.clear(); + AppendInternalKey(&rep_, p); + } + + void Clear() { rep_.clear(); } + + std::string DebugString() const; +}; + +inline int InternalKeyComparator::Compare( + const InternalKey& a, const InternalKey& b) const { + return Compare(a.Encode(), b.Encode()); +} + +inline bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result) { + const size_t n = internal_key.size(); + if (n < 8) return false; + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + result->sequence = num >> 8; + result->type = static_cast(c); + result->user_key = Slice(internal_key.data(), n - 8); + return (c <= static_cast(kTypeValue)); +} + +// A helper class useful for DBImpl::Get() +class LookupKey { + public: + // Initialize *this for looking up user_key at a snapshot with + // the specified sequence number. + LookupKey(const Slice& user_key, SequenceNumber sequence); + + ~LookupKey(); + + // Return a key suitable for lookup in a MemTable. + Slice memtable_key() const { return Slice(start_, end_ - start_); } + + // Return an internal key (suitable for passing to an internal iterator) + Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } + + // Return the user key + Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } + + private: + // We construct a char array of the form: + // klength varint32 <-- start_ + // userkey char[klength] <-- kstart_ + // tag uint64 + // <-- end_ + // The array is a suitable MemTable key. + // The suffix starting with "userkey" can be used as an InternalKey. + const char* start_; + const char* kstart_; + const char* end_; + char space_[200]; // Avoid allocation for short keys + + // No copying allowed + LookupKey(const LookupKey&); + void operator=(const LookupKey&); +}; + +inline LookupKey::~LookupKey() { + if (start_ != space_) delete[] start_; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FORMAT_H_ diff --git a/src/leveldb/db/dbformat_test.cc b/src/leveldb/db/dbformat_test.cc new file mode 100644 index 0000000..5d82f5d --- /dev/null +++ b/src/leveldb/db/dbformat_test.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/dbformat.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string IKey(const std::string& user_key, + uint64_t seq, + ValueType vt) { + std::string encoded; + AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt)); + return encoded; +} + +static std::string Shorten(const std::string& s, const std::string& l) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l); + return result; +} + +static std::string ShortSuccessor(const std::string& s) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result); + return result; +} + +static void TestKey(const std::string& key, + uint64_t seq, + ValueType vt) { + std::string encoded = IKey(key, seq, vt); + + Slice in(encoded); + ParsedInternalKey decoded("", 0, kTypeValue); + + ASSERT_TRUE(ParseInternalKey(in, &decoded)); + ASSERT_EQ(key, decoded.user_key.ToString()); + ASSERT_EQ(seq, decoded.sequence); + ASSERT_EQ(vt, decoded.type); + + ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded)); +} + +class FormatTest { }; + +TEST(FormatTest, InternalKey_EncodeDecode) { + const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" }; + const uint64_t seq[] = { + 1, 2, 3, + (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1, + (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1, + (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1 + }; + for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) { + for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) { + TestKey(keys[k], seq[s], kTypeValue); + TestKey("hello", 1, kTypeDeletion); + } + } +} + +TEST(FormatTest, InternalKeyShortSeparator) { + // When user keys are same + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 99, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 101, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeDeletion))); + + // When user keys are misordered + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("bar", 99, kTypeValue))); + + // When user keys are different, but correctly ordered + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("foo", 100, kTypeValue), + IKey("hello", 200, kTypeValue))); + + // When start user key is prefix of limit user key + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foobar", 200, kTypeValue))); + + // When limit user key is prefix of start user key + ASSERT_EQ(IKey("foobar", 100, kTypeValue), + Shorten(IKey("foobar", 100, kTypeValue), + IKey("foo", 200, kTypeValue))); +} + +TEST(FormatTest, InternalKeyShortestSuccessor) { + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + ShortSuccessor(IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue), + ShortSuccessor(IKey("\xff\xff", 100, kTypeValue))); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/filename.cc b/src/leveldb/db/filename.cc new file mode 100644 index 0000000..3c4d49f --- /dev/null +++ b/src/leveldb/db/filename.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "db/filename.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "util/logging.h" + +namespace leveldb { + +// A utility routine: write "data" to the named file and Sync() it. +extern Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname); + +static std::string MakeFileName(const std::string& name, uint64_t number, + const char* suffix) { + char buf[100]; + snprintf(buf, sizeof(buf), "/%06llu.%s", + static_cast(number), + suffix); + return name + buf; +} + +std::string LogFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "log"); +} + +std::string TableFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "sst"); +} + +std::string DescriptorFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + char buf[100]; + snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", + static_cast(number)); + return dbname + buf; +} + +std::string CurrentFileName(const std::string& dbname) { + return dbname + "/CURRENT"; +} + +std::string LockFileName(const std::string& dbname) { + return dbname + "/LOCK"; +} + +std::string TempFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "dbtmp"); +} + +std::string InfoLogFileName(const std::string& dbname) { + return dbname + "/LOG"; +} + +// Return the name of the old info log file for "dbname". +std::string OldInfoLogFileName(const std::string& dbname) { + return dbname + "/LOG.old"; +} + + +// Owned filenames have the form: +// dbname/CURRENT +// dbname/LOCK +// dbname/LOG +// dbname/LOG.old +// dbname/MANIFEST-[0-9]+ +// dbname/[0-9]+.(log|sst) +bool ParseFileName(const std::string& fname, + uint64_t* number, + FileType* type) { + Slice rest(fname); + if (rest == "CURRENT") { + *number = 0; + *type = kCurrentFile; + } else if (rest == "LOCK") { + *number = 0; + *type = kDBLockFile; + } else if (rest == "LOG" || rest == "LOG.old") { + *number = 0; + *type = kInfoLogFile; + } else if (rest.starts_with("MANIFEST-")) { + rest.remove_prefix(strlen("MANIFEST-")); + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + if (!rest.empty()) { + return false; + } + *type = kDescriptorFile; + *number = num; + } else { + // Avoid strtoull() to keep filename format independent of the + // current locale + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + Slice suffix = rest; + if (suffix == Slice(".log")) { + *type = kLogFile; + } else if (suffix == Slice(".sst")) { + *type = kTableFile; + } else if (suffix == Slice(".dbtmp")) { + *type = kTempFile; + } else { + return false; + } + *number = num; + } + return true; +} + +Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number) { + // Remove leading "dbname/" and add newline to manifest file name + std::string manifest = DescriptorFileName(dbname, descriptor_number); + Slice contents = manifest; + assert(contents.starts_with(dbname + "/")); + contents.remove_prefix(dbname.size() + 1); + std::string tmp = TempFileName(dbname, descriptor_number); + Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); + if (s.ok()) { + s = env->RenameFile(tmp, CurrentFileName(dbname)); + } + if (!s.ok()) { + env->DeleteFile(tmp); + } + return s; +} + +} // namespace leveldb diff --git a/src/leveldb/db/filename.h b/src/leveldb/db/filename.h new file mode 100644 index 0000000..d5d09b1 --- /dev/null +++ b/src/leveldb/db/filename.h @@ -0,0 +1,80 @@ +// 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. +// +// File names used by DB code + +#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ +#define STORAGE_LEVELDB_DB_FILENAME_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +enum FileType { + kLogFile, + kDBLockFile, + kTableFile, + kDescriptorFile, + kCurrentFile, + kTempFile, + kInfoLogFile // Either the current one, or an old one +}; + +// Return the name of the log file with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string LogFileName(const std::string& dbname, uint64_t number); + +// Return the name of the sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string TableFileName(const std::string& dbname, uint64_t number); + +// Return the name of the descriptor file for the db named by +// "dbname" and the specified incarnation number. The result will be +// prefixed with "dbname". +extern std::string DescriptorFileName(const std::string& dbname, + uint64_t number); + +// Return the name of the current file. This file contains the name +// of the current manifest file. The result will be prefixed with +// "dbname". +extern std::string CurrentFileName(const std::string& dbname); + +// Return the name of the lock file for the db named by +// "dbname". The result will be prefixed with "dbname". +extern std::string LockFileName(const std::string& dbname); + +// Return the name of a temporary file owned by the db named "dbname". +// The result will be prefixed with "dbname". +extern std::string TempFileName(const std::string& dbname, uint64_t number); + +// Return the name of the info log file for "dbname". +extern std::string InfoLogFileName(const std::string& dbname); + +// Return the name of the old info log file for "dbname". +extern std::string OldInfoLogFileName(const std::string& dbname); + +// If filename is a leveldb file, store the type of the file in *type. +// The number encoded in the filename is stored in *number. If the +// filename was successfully parsed, returns true. Else return false. +extern bool ParseFileName(const std::string& filename, + uint64_t* number, + FileType* type); + +// Make the CURRENT file point to the descriptor file with the +// specified number. +extern Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number); + + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/src/leveldb/db/filename_test.cc b/src/leveldb/db/filename_test.cc new file mode 100644 index 0000000..5a26da4 --- /dev/null +++ b/src/leveldb/db/filename_test.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/filename.h" + +#include "db/dbformat.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +class FileNameTest { }; + +TEST(FileNameTest, Parse) { + Slice db; + FileType type; + uint64_t number; + + // Successful parses + static struct { + const char* fname; + uint64_t number; + FileType type; + } cases[] = { + { "100.log", 100, kLogFile }, + { "0.log", 0, kLogFile }, + { "0.sst", 0, kTableFile }, + { "CURRENT", 0, kCurrentFile }, + { "LOCK", 0, kDBLockFile }, + { "MANIFEST-2", 2, kDescriptorFile }, + { "MANIFEST-7", 7, kDescriptorFile }, + { "LOG", 0, kInfoLogFile }, + { "LOG.old", 0, kInfoLogFile }, + { "18446744073709551615.log", 18446744073709551615ull, kLogFile }, + }; + for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + std::string f = cases[i].fname; + ASSERT_TRUE(ParseFileName(f, &number, &type)) << f; + ASSERT_EQ(cases[i].type, type) << f; + ASSERT_EQ(cases[i].number, number) << f; + } + + // Errors + static const char* errors[] = { + "", + "foo", + "foo-dx-100.log", + ".log", + "", + "manifest", + "CURREN", + "CURRENTX", + "MANIFES", + "MANIFEST", + "MANIFEST-", + "XMANIFEST-3", + "MANIFEST-3x", + "LOC", + "LOCKx", + "LO", + "LOGx", + "18446744073709551616.log", + "184467440737095516150.log", + "100", + "100.", + "100.lop" + }; + for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { + std::string f = errors[i]; + ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; + } +} + +TEST(FileNameTest, Construction) { + uint64_t number; + FileType type; + std::string fname; + + fname = CurrentFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kCurrentFile, type); + + fname = LockFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kDBLockFile, type); + + fname = LogFileName("foo", 192); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(192, number); + ASSERT_EQ(kLogFile, type); + + fname = TableFileName("bar", 200); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(200, number); + ASSERT_EQ(kTableFile, type); + + fname = DescriptorFileName("bar", 100); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(100, number); + ASSERT_EQ(kDescriptorFile, type); + + fname = TempFileName("tmp", 999); + ASSERT_EQ("tmp/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(999, number); + ASSERT_EQ(kTempFile, type); +} + +} // 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/leveldb_main.cc new file mode 100644 index 0000000..995d761 --- /dev/null +++ b/src/leveldb/db/leveldb_main.cc @@ -0,0 +1,238 @@ +// Copyright (c) 2012 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 +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" + +namespace leveldb { + +namespace { + +bool GuessType(const std::string& fname, FileType* type) { + size_t pos = fname.rfind('/'); + std::string basename; + if (pos == std::string::npos) { + basename = fname; + } else { + basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); + } + uint64_t ignored; + return ParseFileName(basename, &ignored, type); +} + +// Notified when log reader encounters corruption. +class CorruptionReporter : public log::Reader::Reporter { + public: + virtual void Corruption(size_t bytes, const Status& status) { + printf("corruption: %d bytes; %s\n", + static_cast(bytes), + status.ToString().c_str()); + } +}; + +// Print contents of a log file. (*func)() is called on every record. +bool PrintLogContents(Env* env, const std::string& fname, + void (*func)(Slice)) { + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + return false; + } + CorruptionReporter reporter; + log::Reader reader(file, &reporter, true, 0); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch)) { + printf("--- offset %llu; ", + static_cast(reader.LastRecordOffset())); + (*func)(record); + } + delete file; + return true; +} + +// Called on every item found in a WriteBatch. +class WriteBatchItemPrinter : public WriteBatch::Handler { + public: + uint64_t offset_; + uint64_t sequence_; + + virtual void Put(const Slice& key, const Slice& value) { + printf(" put '%s' '%s'\n", + EscapeString(key).c_str(), + EscapeString(value).c_str()); + } + virtual void Delete(const Slice& key) { + printf(" del '%s'\n", + EscapeString(key).c_str()); + } +}; + + +// Called on every log record (each one of which is a WriteBatch) +// found in a kLogFile. +static void WriteBatchPrinter(Slice record) { + if (record.size() < 12) { + printf("log record length %d is too small\n", + static_cast(record.size())); + return; + } + WriteBatch batch; + WriteBatchInternal::SetContents(&batch, record); + printf("sequence %llu\n", + static_cast(WriteBatchInternal::Sequence(&batch))); + WriteBatchItemPrinter batch_item_printer; + Status s = batch.Iterate(&batch_item_printer); + if (!s.ok()) { + printf(" error: %s\n", s.ToString().c_str()); + } +} + +bool DumpLog(Env* env, const std::string& fname) { + return PrintLogContents(env, fname, WriteBatchPrinter); +} + +// Called on every log record (each one of which is a WriteBatch) +// found in a kDescriptorFile. +static void VersionEditPrinter(Slice record) { + VersionEdit edit; + Status s = edit.DecodeFrom(record); + if (!s.ok()) { + printf("%s\n", s.ToString().c_str()); + return; + } + printf("%s", edit.DebugString().c_str()); +} + +bool DumpDescriptor(Env* env, const std::string& fname) { + return PrintLogContents(env, fname, VersionEditPrinter); +} + +bool DumpTable(Env* env, const std::string& fname) { + uint64_t file_size; + RandomAccessFile* file = NULL; + Table* table = NULL; + Status s = env->GetFileSize(fname, &file_size); + if (s.ok()) { + s = env->NewRandomAccessFile(fname, &file); + } + if (s.ok()) { + // We use the default comparator, which may or may not match the + // comparator used in this database. However this should not cause + // problems since we only use Table operations that do not require + // any comparisons. In particular, we do not call Seek or Prev. + s = Table::Open(Options(), file, file_size, &table); + } + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + delete table; + delete file; + return false; + } + + ReadOptions ro; + ro.fill_cache = false; + Iterator* iter = table->NewIterator(ro); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey key; + if (!ParseInternalKey(iter->key(), &key)) { + printf("badkey '%s' => '%s'\n", + EscapeString(iter->key()).c_str(), + EscapeString(iter->value()).c_str()); + } else { + char kbuf[20]; + const char* type; + if (key.type == kTypeDeletion) { + type = "del"; + } else if (key.type == kTypeValue) { + type = "val"; + } else { + snprintf(kbuf, sizeof(kbuf), "%d", static_cast(key.type)); + type = kbuf; + } + printf("'%s' @ %8llu : %s => '%s'\n", + EscapeString(key.user_key).c_str(), + static_cast(key.sequence), + type, + EscapeString(iter->value()).c_str()); + } + } + s = iter->status(); + if (!s.ok()) { + printf("iterator error: %s\n", s.ToString().c_str()); + } + + delete iter; + delete table; + delete file; + return true; +} + +bool DumpFile(Env* env, const std::string& fname) { + FileType ftype; + if (!GuessType(fname, &ftype)) { + fprintf(stderr, "%s: unknown file type\n", fname.c_str()); + return false; + } + switch (ftype) { + case kLogFile: return DumpLog(env, fname); + case kDescriptorFile: return DumpDescriptor(env, fname); + case kTableFile: return DumpTable(env, fname); + + default: { + fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str()); + break; + } + } + return false; +} + +bool HandleDumpCommand(Env* env, char** files, int num) { + bool ok = true; + for (int i = 0; i < num; i++) { + ok &= DumpFile(env, files[i]); + } + return ok; +} + +} +} // namespace leveldb + +static void Usage() { + fprintf( + stderr, + "Usage: leveldbutil command...\n" + " dump files... -- dump contents of specified files\n" + ); +} + +int main(int argc, char** argv) { + leveldb::Env* env = leveldb::Env::Default(); + bool ok = true; + if (argc < 2) { + Usage(); + ok = false; + } else { + std::string command = argv[1]; + if (command == "dump") { + ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); + } else { + Usage(); + ok = false; + } + } + return (ok ? 0 : 1); +} diff --git a/src/leveldb/db/log_format.h b/src/leveldb/db/log_format.h new file mode 100644 index 0000000..2690cb9 --- /dev/null +++ b/src/leveldb/db/log_format.h @@ -0,0 +1,35 @@ +// 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. +// +// Log format information shared by reader and writer. +// See ../doc/log_format.txt for more detail. + +#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ +#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ + +namespace leveldb { +namespace log { + +enum RecordType { + // Zero is reserved for preallocated files + kZeroType = 0, + + kFullType = 1, + + // For fragments + kFirstType = 2, + kMiddleType = 3, + kLastType = 4 +}; +static const int kMaxRecordType = kLastType; + +static const int kBlockSize = 32768; + +// Header is checksum (4 bytes), type (1 byte), length (2 bytes). +static const int kHeaderSize = 4 + 1 + 2; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc new file mode 100644 index 0000000..b35f115 --- /dev/null +++ b/src/leveldb/db/log_reader.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Reader::Reporter::~Reporter() { +} + +Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset) + : file_(file), + reporter_(reporter), + checksum_(checksum), + backing_store_(new char[kBlockSize]), + buffer_(), + eof_(false), + last_record_offset_(0), + end_of_buffer_offset_(0), + initial_offset_(initial_offset) { +} + +Reader::~Reader() { + delete[] backing_store_; +} + +bool Reader::SkipToInitialBlock() { + size_t offset_in_block = initial_offset_ % kBlockSize; + uint64_t block_start_location = initial_offset_ - offset_in_block; + + // Don't search a block if we'd be in the trailer + if (offset_in_block > kBlockSize - 6) { + offset_in_block = 0; + block_start_location += kBlockSize; + } + + end_of_buffer_offset_ = block_start_location; + + // Skip to start of first block that can contain the initial record + if (block_start_location > 0) { + Status skip_status = file_->Skip(block_start_location); + if (!skip_status.ok()) { + ReportDrop(block_start_location, skip_status); + return false; + } + } + + return true; +} + +bool Reader::ReadRecord(Slice* record, std::string* scratch) { + if (last_record_offset_ < initial_offset_) { + if (!SkipToInitialBlock()) { + return false; + } + } + + scratch->clear(); + record->clear(); + bool in_fragmented_record = false; + // Record offset of the logical record that we're reading + // 0 is a dummy value to make compilers happy + uint64_t prospective_record_offset = 0; + + Slice fragment; + while (true) { + uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size(); + const unsigned int record_type = ReadPhysicalRecord(&fragment); + switch (record_type) { + case kFullType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(1)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->clear(); + *record = fragment; + last_record_offset_ = prospective_record_offset; + return true; + + case kFirstType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(2)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->assign(fragment.data(), fragment.size()); + in_fragmented_record = true; + break; + + case kMiddleType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(1)"); + } else { + scratch->append(fragment.data(), fragment.size()); + } + break; + + case kLastType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(2)"); + } else { + scratch->append(fragment.data(), fragment.size()); + *record = Slice(*scratch); + last_record_offset_ = prospective_record_offset; + return true; + } + break; + + case kEof: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "partial record without end(3)"); + scratch->clear(); + } + return false; + + case kBadRecord: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "error in middle of record"); + in_fragmented_record = false; + scratch->clear(); + } + break; + + default: { + char buf[40]; + snprintf(buf, sizeof(buf), "unknown record type %u", record_type); + ReportCorruption( + (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), + buf); + in_fragmented_record = false; + scratch->clear(); + break; + } + } + } + return false; +} + +uint64_t Reader::LastRecordOffset() { + return last_record_offset_; +} + +void Reader::ReportCorruption(size_t bytes, const char* reason) { + ReportDrop(bytes, Status::Corruption(reason)); +} + +void Reader::ReportDrop(size_t bytes, const Status& reason) { + if (reporter_ != NULL && + end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { + reporter_->Corruption(bytes, reason); + } +} + +unsigned int Reader::ReadPhysicalRecord(Slice* result) { + while (true) { + if (buffer_.size() < kHeaderSize) { + if (!eof_) { + // Last read was a full read, so this is a trailer to skip + buffer_.clear(); + Status status = file_->Read(kBlockSize, &buffer_, backing_store_); + end_of_buffer_offset_ += buffer_.size(); + if (!status.ok()) { + buffer_.clear(); + ReportDrop(kBlockSize, status); + eof_ = true; + return kEof; + } else if (buffer_.size() < kBlockSize) { + eof_ = true; + } + continue; + } else if (buffer_.size() == 0) { + // End of file + return kEof; + } else { + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "truncated record at end of file"); + return kEof; + } + } + + // Parse the header + const char* header = buffer_.data(); + const uint32_t a = static_cast(header[4]) & 0xff; + const uint32_t b = static_cast(header[5]) & 0xff; + const unsigned int type = header[6]; + const uint32_t length = a | (b << 8); + if (kHeaderSize + length > buffer_.size()) { + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "bad record length"); + return kBadRecord; + } + + if (type == kZeroType && length == 0) { + // Skip zero length record without reporting any drops since + // such records are produced by the mmap based writing code in + // env_posix.cc that preallocates file regions. + buffer_.clear(); + return kBadRecord; + } + + // Check crc + if (checksum_) { + uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); + uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); + if (actual_crc != expected_crc) { + // Drop the rest of the buffer since "length" itself may have + // been corrupted and if we trust it, we could find some + // fragment of a real log record that just happens to look + // like a valid log record. + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "checksum mismatch"); + return kBadRecord; + } + } + + buffer_.remove_prefix(kHeaderSize + length); + + // Skip physical record that started before initial_offset_ + if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < + initial_offset_) { + result->clear(); + return kBadRecord; + } + + *result = Slice(header + kHeaderSize, length); + return type; + } +} + +} // namespace log +} // namespace leveldb diff --git a/src/leveldb/db/log_reader.h b/src/leveldb/db/log_reader.h new file mode 100644 index 0000000..82d4bee --- /dev/null +++ b/src/leveldb/db/log_reader.h @@ -0,0 +1,108 @@ +// 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_LOG_READER_H_ +#define STORAGE_LEVELDB_DB_LOG_READER_H_ + +#include + +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class SequentialFile; + +namespace log { + +class Reader { + public: + // Interface for reporting errors. + class Reporter { + public: + virtual ~Reporter(); + + // Some corruption was detected. "size" is the approximate number + // of bytes dropped due to the corruption. + virtual void Corruption(size_t bytes, const Status& status) = 0; + }; + + // Create a reader that will return log records from "*file". + // "*file" must remain live while this Reader is in use. + // + // If "reporter" is non-NULL, it is notified whenever some data is + // dropped due to a detected corruption. "*reporter" must remain + // live while this Reader is in use. + // + // If "checksum" is true, verify checksums if available. + // + // The Reader will start reading at the first record located at physical + // position >= initial_offset within the file. + Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset); + + ~Reader(); + + // Read the next record into *record. Returns true if read + // successfully, false if we hit end of the input. May use + // "*scratch" as temporary storage. The contents filled in *record + // will only be valid until the next mutating operation on this + // reader or the next mutation to *scratch. + bool ReadRecord(Slice* record, std::string* scratch); + + // Returns the physical offset of the last record returned by ReadRecord. + // + // Undefined before the first call to ReadRecord. + uint64_t LastRecordOffset(); + + private: + SequentialFile* const file_; + Reporter* const reporter_; + bool const checksum_; + char* const backing_store_; + Slice buffer_; + bool eof_; // Last Read() indicated EOF by returning < kBlockSize + + // Offset of the last record returned by ReadRecord. + uint64_t last_record_offset_; + // Offset of the first location past the end of buffer_. + uint64_t end_of_buffer_offset_; + + // Offset at which to start looking for the first record to return + uint64_t const initial_offset_; + + // Extend record types with the following special values + enum { + kEof = kMaxRecordType + 1, + // Returned whenever we find an invalid physical record. + // Currently there are three situations in which this happens: + // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) + // * The record is a 0-length record (No drop is reported) + // * The record is below constructor's initial_offset (No drop is reported) + kBadRecord = kMaxRecordType + 2 + }; + + // Skips all blocks that are completely before "initial_offset_". + // + // Returns true on success. Handles reporting. + bool SkipToInitialBlock(); + + // Return type, or one of the preceding special values + unsigned int ReadPhysicalRecord(Slice* result); + + // Reports dropped bytes to the reporter. + // buffer_ must be updated to remove the dropped bytes prior to invocation. + void ReportCorruption(size_t bytes, const char* reason); + void ReportDrop(size_t bytes, const Status& reason); + + // No copying allowed + Reader(const Reader&); + void operator=(const Reader&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc new file mode 100644 index 0000000..4c5cf87 --- /dev/null +++ b/src/leveldb/db/log_test.cc @@ -0,0 +1,500 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { +namespace log { + +// Construct a string of the specified length made out of the supplied +// partial string. +static std::string BigString(const std::string& partial_string, size_t n) { + std::string result; + while (result.size() < n) { + result.append(partial_string); + } + result.resize(n); + return result; +} + +// Construct a string from a number +static std::string NumberString(int n) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d.", n); + return std::string(buf); +} + +// Return a skewed potentially long string +static std::string RandomSkewedString(int i, Random* rnd) { + return BigString(NumberString(i), rnd->Skewed(17)); +} + +class LogTest { + private: + class StringDest : public WritableFile { + public: + std::string contents_; + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + virtual Status Append(const Slice& slice) { + contents_.append(slice.data(), slice.size()); + return Status::OK(); + } + }; + + class StringSource : public SequentialFile { + public: + Slice contents_; + bool force_error_; + bool returned_partial_; + StringSource() : force_error_(false), returned_partial_(false) { } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error"; + + if (force_error_) { + force_error_ = false; + returned_partial_ = true; + return Status::Corruption("read error"); + } + + if (contents_.size() < n) { + n = contents_.size(); + returned_partial_ = true; + } + *result = Slice(contents_.data(), n); + contents_.remove_prefix(n); + return Status::OK(); + } + + virtual Status Skip(uint64_t n) { + if (n > contents_.size()) { + contents_.clear(); + return Status::NotFound("in-memory file skipepd past end"); + } + + contents_.remove_prefix(n); + + return Status::OK(); + } + }; + + class ReportCollector : public Reader::Reporter { + public: + size_t dropped_bytes_; + std::string message_; + + ReportCollector() : dropped_bytes_(0) { } + virtual void Corruption(size_t bytes, const Status& status) { + dropped_bytes_ += bytes; + message_.append(status.ToString()); + } + }; + + StringDest dest_; + StringSource source_; + ReportCollector report_; + bool reading_; + 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_[]; + + public: + LogTest() : reading_(false), + writer_(&dest_), + reader_(&source_, &report_, true/*checksum*/, + 0/*initial_offset*/) { + } + + void Write(const std::string& msg) { + ASSERT_TRUE(!reading_) << "Write() after starting to read"; + writer_.AddRecord(Slice(msg)); + } + + size_t WrittenBytes() const { + return dest_.contents_.size(); + } + + std::string Read() { + if (!reading_) { + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + } + std::string scratch; + Slice record; + if (reader_.ReadRecord(&record, &scratch)) { + return record.ToString(); + } else { + return "EOF"; + } + } + + void IncrementByte(int offset, int delta) { + dest_.contents_[offset] += delta; + } + + void SetByte(int offset, char new_byte) { + dest_.contents_[offset] = new_byte; + } + + void ShrinkSize(int bytes) { + dest_.contents_.resize(dest_.contents_.size() - bytes); + } + + void FixChecksum(int header_offset, int len) { + // Compute crc of type/len/data + uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len); + crc = crc32c::Mask(crc); + EncodeFixed32(&dest_.contents_[header_offset], crc); + } + + void ForceError() { + source_.force_error_ = true; + } + + size_t DroppedBytes() const { + return report_.dropped_bytes_; + } + + std::string ReportMessage() const { + return report_.message_; + } + + // Returns OK iff recorded error message contains "msg" + std::string MatchError(const std::string& msg) const { + if (report_.message_.find(msg) == std::string::npos) { + return report_.message_; + } else { + return "OK"; + } + } + + void WriteInitialOffsetLog() { + for (int i = 0; i < 4; i++) { + std::string record(initial_offset_record_sizes_[i], + static_cast('a' + i)); + Write(record); + } + } + + void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + WrittenBytes() + offset_past_end); + Slice record; + std::string scratch; + ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch)); + delete offset_reader; + } + + void CheckInitialOffsetRecord(uint64_t initial_offset, + int expected_record_offset) { + WriteInitialOffsetLog(); + reading_ = true; + 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]); + 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}; + +uint64_t LogTest::initial_offset_last_record_offsets_[] = + {0, + kHeaderSize + 10000, + 2 * (kHeaderSize + 10000), + 2 * (kHeaderSize + 10000) + + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize}; + + +TEST(LogTest, Empty) { + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, ReadWrite) { + Write("foo"); + Write("bar"); + Write(""); + Write("xxxx"); + ASSERT_EQ("foo", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("xxxx", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("EOF", Read()); // Make sure reads at eof work +} + +TEST(LogTest, ManyBlocks) { + for (int i = 0; i < 100000; i++) { + Write(NumberString(i)); + } + for (int i = 0; i < 100000; i++) { + ASSERT_EQ(NumberString(i), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, Fragmentation) { + Write("small"); + Write(BigString("medium", 50000)); + Write(BigString("large", 100000)); + ASSERT_EQ("small", Read()); + ASSERT_EQ(BigString("medium", 50000), Read()); + ASSERT_EQ(BigString("large", 100000), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer2) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, ShortTrailer) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, AlignedEof) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, RandomRead) { + const int N = 500; + Random write_rnd(301); + for (int i = 0; i < N; i++) { + Write(RandomSkewedString(i, &write_rnd)); + } + Random read_rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +// Tests of all the error paths in log_reader.cc follow: + +TEST(LogTest, ReadError) { + Write("foo"); + ForceError(); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("read error")); +} + +TEST(LogTest, BadRecordType) { + Write("foo"); + // Type is stored in header[6] + IncrementByte(6, 100); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("unknown record type")); +} + +TEST(LogTest, TruncatedTrailingRecord) { + Write("foo"); + ShrinkSize(4); // Drop all payload as well as a header byte + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kHeaderSize - 1, DroppedBytes()); + ASSERT_EQ("OK", MatchError("truncated record at end of file")); +} + +TEST(LogTest, BadLength) { + Write("foo"); + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kHeaderSize + 2, DroppedBytes()); + ASSERT_EQ("OK", MatchError("bad record length")); +} + +TEST(LogTest, ChecksumMismatch) { + Write("foo"); + IncrementByte(0, 10); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(10, DroppedBytes()); + ASSERT_EQ("OK", MatchError("checksum mismatch")); +} + +TEST(LogTest, UnexpectedMiddleType) { + Write("foo"); + SetByte(6, kMiddleType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedLastType) { + Write("foo"); + SetByte(6, kLastType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedFullType) { + Write("foo"); + Write("bar"); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, UnexpectedFirstType) { + Write("foo"); + Write(BigString("bar", 100000)); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ(BigString("bar", 100000), Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, ErrorJoinsRecords) { + // Consider two fragmented records: + // first(R1) last(R1) first(R2) last(R2) + // where the middle two fragments disappear. We do not want + // first(R1),last(R2) to get joined and returned as a valid record. + + // Write records that span two blocks + Write(BigString("foo", kBlockSize)); + Write(BigString("bar", kBlockSize)); + Write("correct"); + + // Wipe the middle block + for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) { + SetByte(offset, 'x'); + } + + ASSERT_EQ("correct", Read()); + ASSERT_EQ("EOF", Read()); + const int dropped = DroppedBytes(); + ASSERT_LE(dropped, 2*kBlockSize + 100); + ASSERT_GE(dropped, 2*kBlockSize); +} + +TEST(LogTest, ReadStart) { + CheckInitialOffsetRecord(0, 0); +} + +TEST(LogTest, ReadSecondOneOff) { + CheckInitialOffsetRecord(1, 1); +} + +TEST(LogTest, ReadSecondTenThousand) { + CheckInitialOffsetRecord(10000, 1); +} + +TEST(LogTest, ReadSecondStart) { + CheckInitialOffsetRecord(10007, 1); +} + +TEST(LogTest, ReadThirdOneOff) { + CheckInitialOffsetRecord(10008, 2); +} + +TEST(LogTest, ReadThirdStart) { + CheckInitialOffsetRecord(20014, 2); +} + +TEST(LogTest, ReadFourthOneOff) { + CheckInitialOffsetRecord(20015, 3); +} + +TEST(LogTest, ReadFourthFirstBlockTrailer) { + CheckInitialOffsetRecord(log::kBlockSize - 4, 3); +} + +TEST(LogTest, ReadFourthMiddleBlock) { + CheckInitialOffsetRecord(log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthLastBlock) { + CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthStart) { + CheckInitialOffsetRecord( + 2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, + 3); +} + +TEST(LogTest, ReadEnd) { + CheckOffsetPastEndReturnsNoRecords(0); +} + +TEST(LogTest, ReadPastEnd) { + CheckOffsetPastEndReturnsNoRecords(5); +} + +} // namespace log +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/log_writer.cc b/src/leveldb/db/log_writer.cc new file mode 100644 index 0000000..2da99ac --- /dev/null +++ b/src/leveldb/db/log_writer.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_writer.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Writer::Writer(WritableFile* dest) + : dest_(dest), + block_offset_(0) { + for (int i = 0; i <= kMaxRecordType; i++) { + char t = static_cast(i); + type_crc_[i] = crc32c::Value(&t, 1); + } +} + +Writer::~Writer() { +} + +Status Writer::AddRecord(const Slice& slice) { + const char* ptr = slice.data(); + size_t left = slice.size(); + + // Fragment the record if necessary and emit it. Note that if slice + // is empty, we still want to iterate once to emit a single + // zero-length record + Status s; + bool begin = true; + do { + const int leftover = kBlockSize - block_offset_; + assert(leftover >= 0); + if (leftover < kHeaderSize) { + // Switch to a new block + if (leftover > 0) { + // Fill the trailer (literal below relies on kHeaderSize being 7) + assert(kHeaderSize == 7); + dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); + } + block_offset_ = 0; + } + + // Invariant: we never leave < kHeaderSize bytes in a block. + assert(kBlockSize - block_offset_ - kHeaderSize >= 0); + + const size_t avail = kBlockSize - block_offset_ - kHeaderSize; + const size_t fragment_length = (left < avail) ? left : avail; + + RecordType type; + const bool end = (left == fragment_length); + if (begin && end) { + type = kFullType; + } else if (begin) { + type = kFirstType; + } else if (end) { + type = kLastType; + } else { + type = kMiddleType; + } + + s = EmitPhysicalRecord(type, ptr, fragment_length); + ptr += fragment_length; + left -= fragment_length; + begin = false; + } while (s.ok() && left > 0); + return s; +} + +Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { + assert(n <= 0xffff); // Must fit in two bytes + assert(block_offset_ + kHeaderSize + n <= kBlockSize); + + // Format the header + char buf[kHeaderSize]; + buf[4] = static_cast(n & 0xff); + buf[5] = static_cast(n >> 8); + buf[6] = static_cast(t); + + // Compute the crc of the record type and the payload. + uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); + crc = crc32c::Mask(crc); // Adjust for storage + EncodeFixed32(buf, crc); + + // Write the header and the payload + Status s = dest_->Append(Slice(buf, kHeaderSize)); + if (s.ok()) { + s = dest_->Append(Slice(ptr, n)); + if (s.ok()) { + s = dest_->Flush(); + } + } + block_offset_ += kHeaderSize + n; + return s; +} + +} // namespace log +} // namespace leveldb diff --git a/src/leveldb/db/log_writer.h b/src/leveldb/db/log_writer.h new file mode 100644 index 0000000..a3a954d --- /dev/null +++ b/src/leveldb/db/log_writer.h @@ -0,0 +1,48 @@ +// 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_LOG_WRITER_H_ +#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ + +#include +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class WritableFile; + +namespace log { + +class Writer { + public: + // Create a writer that will append data to "*dest". + // "*dest" must be initially empty. + // "*dest" must remain live while this Writer is in use. + explicit Writer(WritableFile* dest); + ~Writer(); + + Status AddRecord(const Slice& slice); + + private: + WritableFile* dest_; + int block_offset_; // Current offset in block + + // crc32c values for all supported record types. These are + // pre-computed to reduce the overhead of computing the crc of the + // record type stored in the header. + uint32_t type_crc_[kMaxRecordType + 1]; + + Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); + + // No copying allowed + Writer(const Writer&); + void operator=(const Writer&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc new file mode 100644 index 0000000..bfec0a7 --- /dev/null +++ b/src/leveldb/db/memtable.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/memtable.h" +#include "db/dbformat.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "util/coding.h" + +namespace leveldb { + +static Slice GetLengthPrefixedSlice(const char* data) { + uint32_t len; + const char* p = data; + p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted + return Slice(p, len); +} + +MemTable::MemTable(const InternalKeyComparator& cmp) + : comparator_(cmp), + refs_(0), + table_(comparator_, &arena_) { +} + +MemTable::~MemTable() { + assert(refs_ == 0); +} + +size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } + +int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) + const { + // Internal keys are encoded as length-prefixed strings. + Slice a = GetLengthPrefixedSlice(aptr); + Slice b = GetLengthPrefixedSlice(bptr); + return comparator.Compare(a, b); +} + +// Encode a suitable internal key target for "target" and return it. +// Uses *scratch as scratch space, and the returned pointer will point +// into this scratch space. +static const char* EncodeKey(std::string* scratch, const Slice& target) { + scratch->clear(); + PutVarint32(scratch, target.size()); + scratch->append(target.data(), target.size()); + return scratch->data(); +} + +class MemTableIterator: public Iterator { + public: + explicit MemTableIterator(MemTable::Table* table) : iter_(table) { } + + virtual bool Valid() const { return iter_.Valid(); } + virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } + virtual void SeekToFirst() { iter_.SeekToFirst(); } + virtual void SeekToLast() { iter_.SeekToLast(); } + virtual void Next() { iter_.Next(); } + virtual void Prev() { iter_.Prev(); } + virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } + virtual Slice value() const { + Slice key_slice = GetLengthPrefixedSlice(iter_.key()); + return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); + } + + virtual Status status() const { return Status::OK(); } + + private: + MemTable::Table::Iterator iter_; + std::string tmp_; // For passing to EncodeKey + + // No copying allowed + MemTableIterator(const MemTableIterator&); + void operator=(const MemTableIterator&); +}; + +Iterator* MemTable::NewIterator() { + return new MemTableIterator(&table_); +} + +void MemTable::Add(SequenceNumber s, ValueType type, + const Slice& key, + const Slice& value) { + // Format of an entry is concatenation of: + // key_size : varint32 of internal_key.size() + // key bytes : char[internal_key.size()] + // value_size : varint32 of value.size() + // value bytes : char[value.size()] + size_t key_size = key.size(); + size_t val_size = value.size(); + size_t internal_key_size = key_size + 8; + const size_t encoded_len = + VarintLength(internal_key_size) + internal_key_size + + VarintLength(val_size) + val_size; + char* buf = arena_.Allocate(encoded_len); + char* p = EncodeVarint32(buf, internal_key_size); + memcpy(p, key.data(), key_size); + p += key_size; + EncodeFixed64(p, (s << 8) | type); + p += 8; + p = EncodeVarint32(p, val_size); + memcpy(p, value.data(), val_size); + assert((p + val_size) - buf == encoded_len); + table_.Insert(buf); +} + +bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { + Slice memkey = key.memtable_key(); + Table::Iterator iter(&table_); + iter.Seek(memkey.data()); + if (iter.Valid()) { + // entry format is: + // klength varint32 + // userkey char[klength] + // tag uint64 + // vlength varint32 + // value char[vlength] + // Check that it belongs to same user key. We do not check the + // sequence number since the Seek() call above should have skipped + // all entries with overly large sequence numbers. + const char* entry = iter.key(); + uint32_t key_length; + const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); + if (comparator_.comparator.user_comparator()->Compare( + Slice(key_ptr, key_length - 8), + key.user_key()) == 0) { + // Correct user key + const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); + switch (static_cast(tag & 0xff)) { + case kTypeValue: { + Slice v = GetLengthPrefixedSlice(key_ptr + key_length); + value->assign(v.data(), v.size()); + return true; + } + case kTypeDeletion: + *s = Status::NotFound(Slice()); + return true; + } + } + } + return false; +} + +} // namespace leveldb diff --git a/src/leveldb/db/memtable.h b/src/leveldb/db/memtable.h new file mode 100644 index 0000000..92e90bb --- /dev/null +++ b/src/leveldb/db/memtable.h @@ -0,0 +1,91 @@ +// 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_MEMTABLE_H_ +#define STORAGE_LEVELDB_DB_MEMTABLE_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/skiplist.h" +#include "util/arena.h" + +namespace leveldb { + +class InternalKeyComparator; +class Mutex; +class MemTableIterator; + +class MemTable { + public: + // MemTables are reference counted. The initial reference count + // is zero and the caller must call Ref() at least once. + explicit MemTable(const InternalKeyComparator& comparator); + + // Increase reference count. + void Ref() { ++refs_; } + + // Drop reference count. Delete if no more references exist. + void Unref() { + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + delete this; + } + } + + // 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. + size_t ApproximateMemoryUsage(); + + // Return an iterator that yields the contents of the memtable. + // + // The caller must ensure that the underlying MemTable remains live + // while the returned iterator is live. The keys returned by this + // iterator are internal keys encoded by AppendInternalKey in the + // db/format.{h,cc} module. + Iterator* NewIterator(); + + // Add an entry into memtable that maps key to value at the + // specified sequence number and with the specified type. + // Typically value will be empty if type==kTypeDeletion. + void Add(SequenceNumber seq, ValueType type, + const Slice& key, + const Slice& value); + + // If memtable contains a value for key, store it in *value and return true. + // If memtable contains a deletion for key, store a NotFound() error + // in *status and return true. + // Else, return false. + bool Get(const LookupKey& key, std::string* value, Status* s); + + private: + ~MemTable(); // Private since only Unref() should be used to delete it + + struct KeyComparator { + const InternalKeyComparator comparator; + explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { } + int operator()(const char* a, const char* b) const; + }; + friend class MemTableIterator; + friend class MemTableBackwardIterator; + + typedef SkipList Table; + + KeyComparator comparator_; + int refs_; + Arena arena_; + Table table_; + + // No copying allowed + MemTable(const MemTable&); + void operator=(const MemTable&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc new file mode 100644 index 0000000..022d52f --- /dev/null +++ b/src/leveldb/db/repair.cc @@ -0,0 +1,389 @@ +// 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. +// +// We recover the contents of the descriptor from the other files we find. +// (1) Any log files are first converted to tables +// (2) We scan every table to compute +// (a) smallest/largest for the table +// (b) largest sequence number in the table +// (3) We generate descriptor contents: +// - log number is set to zero +// - next-file-number is set to 1 + largest file number we found +// - last-sequence-number is set to largest sequence# found across +// all tables (see 2c) +// - compaction pointers are cleared +// - every table file is added at level 0 +// +// Possible optimization 1: +// (a) Compute total size and use to pick appropriate max-level M +// (b) Sort tables by largest sequence# in the table +// (c) For each table: if it overlaps earlier table, place in level-0, +// else place in level-M. +// Possible optimization 2: +// Store per-table metadata (smallest, largest, largest-seq#, ...) +// in the table's meta section to speed up ScanTable. + +#include "db/builder.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" + +namespace leveldb { + +namespace { + +class Repairer { + public: + Repairer(const std::string& dbname, const Options& options) + : dbname_(dbname), + env_(options.env), + icmp_(options.comparator), + ipolicy_(options.filter_policy), + options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), + owns_info_log_(options_.info_log != options.info_log), + owns_cache_(options_.block_cache != options.block_cache), + next_file_number_(1) { + // TableCache can be small since we expect each table to be opened once. + table_cache_ = new TableCache(dbname_, &options_, 10); + } + + ~Repairer() { + delete table_cache_; + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } + } + + Status Run() { + Status status = FindFiles(); + if (status.ok()) { + ConvertLogFilesToTables(); + ExtractMetaData(); + status = WriteDescriptor(); + } + if (status.ok()) { + unsigned long long bytes = 0; + for (size_t i = 0; i < tables_.size(); i++) { + bytes += tables_[i].meta.file_size; + } + Log(options_.info_log, + "**** Repaired leveldb %s; " + "recovered %d files; %llu bytes. " + "Some data may have been lost. " + "****", + dbname_.c_str(), + static_cast(tables_.size()), + bytes); + } + return status; + } + + private: + struct TableInfo { + FileMetaData meta; + SequenceNumber max_sequence; + }; + + std::string const dbname_; + Env* const env_; + InternalKeyComparator const icmp_; + InternalFilterPolicy const ipolicy_; + Options const options_; + bool owns_info_log_; + bool owns_cache_; + TableCache* table_cache_; + VersionEdit edit_; + + std::vector manifests_; + std::vector table_numbers_; + std::vector logs_; + std::vector tables_; + uint64_t next_file_number_; + + Status FindFiles() { + std::vector filenames; + Status status = env_->GetChildren(dbname_, &filenames); + if (!status.ok()) { + return status; + } + if (filenames.empty()) { + return Status::IOError(dbname_, "repair found no files"); + } + + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + if (type == kDescriptorFile) { + manifests_.push_back(filenames[i]); + } else { + if (number + 1 > next_file_number_) { + next_file_number_ = number + 1; + } + if (type == kLogFile) { + logs_.push_back(number); + } else if (type == kTableFile) { + table_numbers_.push_back(number); + } else { + // Ignore other files + } + } + } + } + return status; + } + + void ConvertLogFilesToTables() { + for (size_t i = 0; i < logs_.size(); i++) { + std::string logname = LogFileName(dbname_, logs_[i]); + Status status = ConvertLogToTable(logs_[i]); + if (!status.ok()) { + Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", + (unsigned long long) logs_[i], + status.ToString().c_str()); + } + ArchiveFile(logname); + } + } + + Status ConvertLogToTable(uint64_t log) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + uint64_t lognum; + virtual void Corruption(size_t bytes, const Status& s) { + // We print error messages for corruption, but continue repairing. + Log(info_log, "Log #%llu: dropping %d bytes; %s", + (unsigned long long) lognum, + static_cast(bytes), + s.ToString().c_str()); + } + }; + + // Open the log file + std::string logname = LogFileName(dbname_, log); + SequentialFile* lfile; + Status status = env_->NewSequentialFile(logname, &lfile); + if (!status.ok()) { + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.lognum = log; + // We intentially make log::Reader do checksumming so that + // corruptions cause entire commits to be skipped instead of + // propagating bad information (like overly large sequence + // numbers). + log::Reader reader(lfile, &reporter, false/*do not checksum*/, + 0/*initial_offset*/); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = new MemTable(icmp_); + mem->Ref(); + int counter = 0; + while (reader.ReadRecord(&record, &scratch)) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + status = WriteBatchInternal::InsertInto(&batch, mem); + if (status.ok()) { + counter += WriteBatchInternal::Count(&batch); + } else { + Log(options_.info_log, "Log #%llu: ignoring %s", + (unsigned long long) log, + status.ToString().c_str()); + status = Status::OK(); // Keep going with rest of file + } + } + delete lfile; + + // Do not record a version edit for this conversion to a Table + // since ExtractMetaData() will also generate edits. + FileMetaData meta; + meta.number = next_file_number_++; + Iterator* iter = mem->NewIterator(); + status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + delete iter; + mem->Unref(); + mem = NULL; + if (status.ok()) { + if (meta.file_size > 0) { + table_numbers_.push_back(meta.number); + } + } + Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", + (unsigned long long) log, + counter, + (unsigned long long) meta.number, + status.ToString().c_str()); + return status; + } + + void ExtractMetaData() { + std::vector kept; + for (size_t i = 0; i < table_numbers_.size(); i++) { + TableInfo t; + t.meta.number = table_numbers_[i]; + Status status = ScanTable(&t); + if (!status.ok()) { + std::string fname = TableFileName(dbname_, table_numbers_[i]); + Log(options_.info_log, "Table #%llu: ignoring %s", + (unsigned long long) table_numbers_[i], + status.ToString().c_str()); + ArchiveFile(fname); + } else { + tables_.push_back(t); + } + } + } + + Status ScanTable(TableInfo* t) { + std::string fname = TableFileName(dbname_, t->meta.number); + int counter = 0; + Status status = env_->GetFileSize(fname, &t->meta.file_size); + if (status.ok()) { + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), t->meta.number, t->meta.file_size); + bool empty = true; + ParsedInternalKey parsed; + t->max_sequence = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + Slice key = iter->key(); + if (!ParseInternalKey(key, &parsed)) { + Log(options_.info_log, "Table #%llu: unparsable key %s", + (unsigned long long) t->meta.number, + EscapeString(key).c_str()); + continue; + } + + counter++; + if (empty) { + empty = false; + t->meta.smallest.DecodeFrom(key); + } + t->meta.largest.DecodeFrom(key); + if (parsed.sequence > t->max_sequence) { + t->max_sequence = parsed.sequence; + } + } + if (!iter->status().ok()) { + status = iter->status(); + } + delete iter; + } + Log(options_.info_log, "Table #%llu: %d entries %s", + (unsigned long long) t->meta.number, + counter, + status.ToString().c_str()); + return status; + } + + Status WriteDescriptor() { + std::string tmp = TempFileName(dbname_, 1); + WritableFile* file; + Status status = env_->NewWritableFile(tmp, &file); + if (!status.ok()) { + return status; + } + + SequenceNumber max_sequence = 0; + for (size_t i = 0; i < tables_.size(); i++) { + if (max_sequence < tables_[i].max_sequence) { + max_sequence = tables_[i].max_sequence; + } + } + + edit_.SetComparatorName(icmp_.user_comparator()->Name()); + edit_.SetLogNumber(0); + edit_.SetNextFile(next_file_number_); + edit_.SetLastSequence(max_sequence); + + for (size_t i = 0; i < tables_.size(); i++) { + // TODO(opt): separate out into multiple levels + const TableInfo& t = tables_[i]; + edit_.AddFile(0, t.meta.number, t.meta.file_size, + t.meta.smallest, t.meta.largest); + } + + //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); + { + log::Writer log(file); + std::string record; + edit_.EncodeTo(&record); + status = log.AddRecord(record); + } + if (status.ok()) { + status = file->Close(); + } + delete file; + file = NULL; + + if (!status.ok()) { + env_->DeleteFile(tmp); + } else { + // Discard older manifests + for (size_t i = 0; i < manifests_.size(); i++) { + ArchiveFile(dbname_ + "/" + manifests_[i]); + } + + // Install new manifest + status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); + if (status.ok()) { + status = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(tmp); + } + } + return status; + } + + void ArchiveFile(const std::string& fname) { + // Move into another directory. E.g., for + // dir/foo + // rename to + // dir/lost/foo + const char* slash = strrchr(fname.c_str(), '/'); + std::string new_dir; + if (slash != NULL) { + new_dir.assign(fname.data(), slash - fname.data()); + } + new_dir.append("/lost"); + env_->CreateDir(new_dir); // Ignore error + std::string new_file = new_dir; + new_file.append("/"); + new_file.append((slash == NULL) ? fname.c_str() : slash + 1); + Status s = env_->RenameFile(fname, new_file); + Log(options_.info_log, "Archiving %s: %s\n", + fname.c_str(), s.ToString().c_str()); + } +}; +} // namespace + +Status RepairDB(const std::string& dbname, const Options& options) { + Repairer repairer(dbname, options); + return repairer.Run(); +} + +} // namespace leveldb diff --git a/src/leveldb/db/skiplist.h b/src/leveldb/db/skiplist.h new file mode 100644 index 0000000..af85be6 --- /dev/null +++ b/src/leveldb/db/skiplist.h @@ -0,0 +1,379 @@ +// 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. +// +// Thread safety +// ------------- +// +// Writes require external synchronization, most likely a mutex. +// Reads require a guarantee that the SkipList will not be destroyed +// while the read is in progress. Apart from that, reads progress +// without any internal locking or synchronization. +// +// Invariants: +// +// (1) Allocated nodes are never deleted until the SkipList is +// destroyed. This is trivially guaranteed by the code since we +// never delete any skip list nodes. +// +// (2) The contents of a Node except for the next/prev pointers are +// immutable after the Node has been linked into the SkipList. +// Only Insert() modifies the list, and it is careful to initialize +// a node and use release-stores to publish the nodes in one or +// more lists. +// +// ... prev vs. next pointer ordering ... + +#include +#include +#include "port/port.h" +#include "util/arena.h" +#include "util/random.h" + +namespace leveldb { + +class Arena; + +template +class SkipList { + private: + struct Node; + + public: + // Create a new SkipList object that will use "cmp" for comparing keys, + // and will allocate memory using "*arena". Objects allocated in the arena + // must remain allocated for the lifetime of the skiplist object. + explicit SkipList(Comparator cmp, Arena* arena); + + // Insert key into the list. + // REQUIRES: nothing that compares equal to key is currently in the list. + void Insert(const Key& key); + + // Returns true iff an entry that compares equal to key is in the list. + bool Contains(const Key& key) const; + + // Iteration over the contents of a skip list + class Iterator { + public: + // Initialize an iterator over the specified list. + // The returned iterator is not valid. + explicit Iterator(const SkipList* list); + + // Returns true iff the iterator is positioned at a valid node. + bool Valid() const; + + // Returns the key at the current position. + // REQUIRES: Valid() + const Key& key() const; + + // Advances to the next position. + // REQUIRES: Valid() + void Next(); + + // Advances to the previous position. + // REQUIRES: Valid() + void Prev(); + + // Advance to the first entry with a key >= target + void Seek(const Key& target); + + // Position at the first entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToFirst(); + + // Position at the last entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToLast(); + + private: + const SkipList* list_; + Node* node_; + // Intentionally copyable + }; + + private: + enum { kMaxHeight = 12 }; + + // Immutable after construction + Comparator const compare_; + Arena* const arena_; // Arena used for allocations of nodes + + Node* const head_; + + // Modified only by Insert(). Read racily by readers, but stale + // values are ok. + port::AtomicPointer max_height_; // Height of the entire list + + inline int GetMaxHeight() const { + return static_cast( + reinterpret_cast(max_height_.NoBarrier_Load())); + } + + // Read/written only by Insert(). + Random rnd_; + + Node* NewNode(const Key& key, int height); + int RandomHeight(); + bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } + + // Return true if key is greater than the data stored in "n" + bool KeyIsAfterNode(const Key& key, Node* n) const; + + // Return the earliest node that comes at or after key. + // Return NULL if there is no such node. + // + // If prev is non-NULL, fills prev[level] with pointer to previous + // node at "level" for every level in [0..max_height_-1]. + Node* FindGreaterOrEqual(const Key& key, Node** prev) const; + + // Return the latest node with a key < key. + // Return head_ if there is no such node. + Node* FindLessThan(const Key& key) const; + + // Return the last node in the list. + // Return head_ if list is empty. + Node* FindLast() const; + + // No copying allowed + SkipList(const SkipList&); + void operator=(const SkipList&); +}; + +// Implementation details follow +template +struct SkipList::Node { + explicit Node(const Key& k) : key(k) { } + + Key const key; + + // Accessors/mutators for links. Wrapped in methods so we can + // add the appropriate barriers as necessary. + Node* Next(int n) { + assert(n >= 0); + // Use an 'acquire load' so that we observe a fully initialized + // version of the returned Node. + return reinterpret_cast(next_[n].Acquire_Load()); + } + void SetNext(int n, Node* x) { + assert(n >= 0); + // Use a 'release store' so that anybody who reads through this + // pointer observes a fully initialized version of the inserted node. + next_[n].Release_Store(x); + } + + // No-barrier variants that can be safely used in a few locations. + Node* NoBarrier_Next(int n) { + assert(n >= 0); + return reinterpret_cast(next_[n].NoBarrier_Load()); + } + void NoBarrier_SetNext(int n, Node* x) { + assert(n >= 0); + next_[n].NoBarrier_Store(x); + } + + private: + // Array of length equal to the node height. next_[0] is lowest level link. + port::AtomicPointer next_[1]; +}; + +template +typename SkipList::Node* +SkipList::NewNode(const Key& key, int height) { + char* mem = arena_->AllocateAligned( + sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); + return new (mem) Node(key); +} + +template +inline SkipList::Iterator::Iterator(const SkipList* list) { + list_ = list; + node_ = NULL; +} + +template +inline bool SkipList::Iterator::Valid() const { + return node_ != NULL; +} + +template +inline const Key& SkipList::Iterator::key() const { + assert(Valid()); + return node_->key; +} + +template +inline void SkipList::Iterator::Next() { + assert(Valid()); + node_ = node_->Next(0); +} + +template +inline void SkipList::Iterator::Prev() { + // Instead of using explicit "prev" links, we just search for the + // last node that falls before key. + assert(Valid()); + node_ = list_->FindLessThan(node_->key); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +inline void SkipList::Iterator::Seek(const Key& target) { + node_ = list_->FindGreaterOrEqual(target, NULL); +} + +template +inline void SkipList::Iterator::SeekToFirst() { + node_ = list_->head_->Next(0); +} + +template +inline void SkipList::Iterator::SeekToLast() { + node_ = list_->FindLast(); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +int SkipList::RandomHeight() { + // Increase height with probability 1 in kBranching + static const unsigned int kBranching = 4; + int height = 1; + while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { + height++; + } + assert(height > 0); + assert(height <= kMaxHeight); + return height; +} + +template +bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { + // NULL n is considered infinite + return (n != NULL) && (compare_(n->key, key) < 0); +} + +template +typename SkipList::Node* SkipList::FindGreaterOrEqual(const Key& key, Node** prev) + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (KeyIsAfterNode(key, next)) { + // Keep searching in this list + x = next; + } else { + if (prev != NULL) prev[level] = x; + if (level == 0) { + return next; + } else { + // Switch to next list + level--; + } + } + } +} + +template +typename SkipList::Node* +SkipList::FindLessThan(const Key& key) const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + assert(x == head_ || compare_(x->key, key) < 0); + Node* next = x->Next(level); + if (next == NULL || compare_(next->key, key) >= 0) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +typename SkipList::Node* SkipList::FindLast() + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (next == NULL) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +SkipList::SkipList(Comparator cmp, Arena* arena) + : compare_(cmp), + arena_(arena), + head_(NewNode(0 /* any key will do */, kMaxHeight)), + max_height_(reinterpret_cast(1)), + rnd_(0xdeadbeef) { + for (int i = 0; i < kMaxHeight; i++) { + head_->SetNext(i, NULL); + } +} + +template +void SkipList::Insert(const Key& key) { + // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() + // here since Insert() is externally synchronized. + Node* prev[kMaxHeight]; + Node* x = FindGreaterOrEqual(key, prev); + + // Our data structure does not allow duplicate insertion + assert(x == NULL || !Equal(key, x->key)); + + int height = RandomHeight(); + if (height > GetMaxHeight()) { + for (int i = GetMaxHeight(); i < height; i++) { + prev[i] = head_; + } + //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); + + // It is ok to mutate max_height_ without any synchronization + // with concurrent readers. A concurrent reader that observes + // the new value of max_height_ will see either the old value of + // new level pointers from head_ (NULL), or a new value set in + // the loop below. In the former case the reader will + // immediately drop to the next level since NULL sorts after all + // keys. In the latter case the reader will use the new node. + max_height_.NoBarrier_Store(reinterpret_cast(height)); + } + + x = NewNode(key, height); + for (int i = 0; i < height; i++) { + // NoBarrier_SetNext() suffices since we will add a barrier when + // we publish a pointer to "x" in prev[i]. + x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); + prev[i]->SetNext(i, x); + } +} + +template +bool SkipList::Contains(const Key& key) const { + Node* x = FindGreaterOrEqual(key, NULL); + if (x != NULL && Equal(key, x->key)) { + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/src/leveldb/db/skiplist_test.cc b/src/leveldb/db/skiplist_test.cc new file mode 100644 index 0000000..c78f4b4 --- /dev/null +++ b/src/leveldb/db/skiplist_test.cc @@ -0,0 +1,378 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/skiplist.h" +#include +#include "leveldb/env.h" +#include "util/arena.h" +#include "util/hash.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +typedef uint64_t Key; + +struct Comparator { + int operator()(const Key& a, const Key& b) const { + if (a < b) { + return -1; + } else if (a > b) { + return +1; + } else { + return 0; + } + } +}; + +class SkipTest { }; + +TEST(SkipTest, Empty) { + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + ASSERT_TRUE(!list.Contains(10)); + + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToFirst(); + ASSERT_TRUE(!iter.Valid()); + iter.Seek(100); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToLast(); + ASSERT_TRUE(!iter.Valid()); +} + +TEST(SkipTest, InsertAndLookup) { + const int N = 2000; + const int R = 5000; + Random rnd(1000); + std::set keys; + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + for (int i = 0; i < N; i++) { + Key key = rnd.Next() % R; + if (keys.insert(key).second) { + list.Insert(key); + } + } + + for (int i = 0; i < R; i++) { + if (list.Contains(i)) { + ASSERT_EQ(keys.count(i), 1); + } else { + ASSERT_EQ(keys.count(i), 0); + } + } + + // Simple iterator tests + { + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + + iter.Seek(0); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToFirst(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToLast(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.rbegin()), iter.key()); + } + + // Forward iteration test + for (int i = 0; i < R; i++) { + SkipList::Iterator iter(&list); + iter.Seek(i); + + // Compare against model iterator + std::set::iterator model_iter = keys.lower_bound(i); + for (int j = 0; j < 3; j++) { + if (model_iter == keys.end()) { + ASSERT_TRUE(!iter.Valid()); + break; + } else { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + ++model_iter; + iter.Next(); + } + } + } + + // Backward iteration test + { + SkipList::Iterator iter(&list); + iter.SeekToLast(); + + // Compare against model iterator + for (std::set::reverse_iterator model_iter = keys.rbegin(); + model_iter != keys.rend(); + ++model_iter) { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + iter.Prev(); + } + ASSERT_TRUE(!iter.Valid()); + } +} + +// We want to make sure that with a single writer and multiple +// concurrent readers (with no synchronization other than when a +// reader's iterator is created), the reader always observes all the +// data that was present in the skip list when the iterator was +// constructor. Because insertions are happening concurrently, we may +// also observe new values that were inserted since the iterator was +// constructed, but we should never miss any values that were present +// at iterator construction time. +// +// We generate multi-part keys: +// +// where: +// key is in range [0..K-1] +// gen is a generation number for key +// hash is hash(key,gen) +// +// The insertion code picks a random key, sets gen to be 1 + the last +// generation number inserted for that key, and sets hash to Hash(key,gen). +// +// At the beginning of a read, we snapshot the last inserted +// generation number for each key. We then iterate, including random +// calls to Next() and Seek(). For every key we encounter, we +// check that it is either expected given the initial snapshot or has +// been concurrently added since the iterator started. +class ConcurrentTest { + private: + static const uint32_t K = 4; + + static uint64_t key(Key key) { return (key >> 40); } + static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; } + static uint64_t hash(Key key) { return key & 0xff; } + + static uint64_t HashNumbers(uint64_t k, uint64_t g) { + uint64_t data[2] = { k, g }; + return Hash(reinterpret_cast(data), sizeof(data), 0); + } + + static Key MakeKey(uint64_t k, uint64_t g) { + assert(sizeof(Key) == sizeof(uint64_t)); + assert(k <= K); // We sometimes pass K to seek to the end of the skiplist + assert(g <= 0xffffffffu); + return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff)); + } + + static bool IsValidKey(Key k) { + return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff); + } + + static Key RandomTarget(Random* rnd) { + switch (rnd->Next() % 10) { + case 0: + // Seek to beginning + return MakeKey(0, 0); + case 1: + // Seek to end + return MakeKey(K, 0); + default: + // Seek to middle + return MakeKey(rnd->Next() % K, 0); + } + } + + // Per-key generation + struct State { + port::AtomicPointer generation[K]; + void Set(int k, intptr_t v) { + generation[k].Release_Store(reinterpret_cast(v)); + } + intptr_t Get(int k) { + return reinterpret_cast(generation[k].Acquire_Load()); + } + + State() { + for (int k = 0; k < K; k++) { + Set(k, 0); + } + } + }; + + // Current state of the test + State current_; + + Arena arena_; + + // SkipList is not protected by mu_. We just use a single writer + // thread to modify it. + SkipList list_; + + public: + ConcurrentTest() : list_(Comparator(), &arena_) { } + + // REQUIRES: External synchronization + void WriteStep(Random* rnd) { + const uint32_t k = rnd->Next() % K; + const intptr_t g = current_.Get(k) + 1; + const Key key = MakeKey(k, g); + list_.Insert(key); + current_.Set(k, g); + } + + void ReadStep(Random* rnd) { + // Remember the initial committed state of the skiplist. + State initial_state; + for (int k = 0; k < K; k++) { + initial_state.Set(k, current_.Get(k)); + } + + Key pos = RandomTarget(rnd); + SkipList::Iterator iter(&list_); + iter.Seek(pos); + while (true) { + Key current; + if (!iter.Valid()) { + current = MakeKey(K, 0); + } else { + current = iter.key(); + ASSERT_TRUE(IsValidKey(current)) << current; + } + ASSERT_LE(pos, current) << "should not go backwards"; + + // Verify that everything in [pos,current) was not present in + // initial_state. + while (pos < current) { + ASSERT_LT(key(pos), K) << pos; + + // 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))) + ) << "key: " << key(pos) + << "; gen: " << gen(pos) + << "; initgen: " + << initial_state.Get(key(pos)); + + // Advance to next key in the valid key space + if (key(pos) < key(current)) { + pos = MakeKey(key(pos) + 1, 0); + } else { + pos = MakeKey(key(pos), gen(pos) + 1); + } + } + + if (!iter.Valid()) { + break; + } + + if (rnd->Next() % 2) { + iter.Next(); + pos = MakeKey(key(pos), gen(pos) + 1); + } else { + Key new_target = RandomTarget(rnd); + if (new_target > pos) { + pos = new_target; + iter.Seek(new_target); + } + } + } + } +}; +const uint32_t ConcurrentTest::K; + +// Simple test that does single-threaded testing of the ConcurrentTest +// scaffolding. +TEST(SkipTest, ConcurrentWithoutThreads) { + ConcurrentTest test; + Random rnd(test::RandomSeed()); + for (int i = 0; i < 10000; i++) { + test.ReadStep(&rnd); + test.WriteStep(&rnd); + } +} + +class TestState { + public: + ConcurrentTest t_; + int seed_; + port::AtomicPointer quit_flag_; + + enum ReaderState { + STARTING, + RUNNING, + DONE + }; + + explicit TestState(int s) + : seed_(s), + quit_flag_(NULL), + state_(STARTING), + state_cv_(&mu_) {} + + void Wait(ReaderState s) { + mu_.Lock(); + while (state_ != s) { + state_cv_.Wait(); + } + mu_.Unlock(); + } + + void Change(ReaderState s) { + mu_.Lock(); + state_ = s; + state_cv_.Signal(); + mu_.Unlock(); + } + + private: + port::Mutex mu_; + ReaderState state_; + port::CondVar state_cv_; +}; + +static void ConcurrentReader(void* arg) { + TestState* state = reinterpret_cast(arg); + Random rnd(state->seed_); + int64_t reads = 0; + state->Change(TestState::RUNNING); + while (!state->quit_flag_.Acquire_Load()) { + state->t_.ReadStep(&rnd); + ++reads; + } + state->Change(TestState::DONE); +} + +static void RunConcurrent(int run) { + const int seed = test::RandomSeed() + (run * 100); + Random rnd(seed); + const int N = 1000; + const int kSize = 1000; + for (int i = 0; i < N; i++) { + if ((i % 100) == 0) { + fprintf(stderr, "Run %d of %d\n", i, N); + } + TestState state(seed + 1); + Env::Default()->Schedule(ConcurrentReader, &state); + state.Wait(TestState::RUNNING); + for (int i = 0; i < kSize; i++) { + state.t_.WriteStep(&rnd); + } + state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do + state.Wait(TestState::DONE); + } +} + +TEST(SkipTest, Concurrent1) { RunConcurrent(1); } +TEST(SkipTest, Concurrent2) { RunConcurrent(2); } +TEST(SkipTest, Concurrent3) { RunConcurrent(3); } +TEST(SkipTest, Concurrent4) { RunConcurrent(4); } +TEST(SkipTest, Concurrent5) { RunConcurrent(5); } + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/snapshot.h b/src/leveldb/db/snapshot.h new file mode 100644 index 0000000..e7f8fd2 --- /dev/null +++ b/src/leveldb/db/snapshot.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ +#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ + +#include "leveldb/db.h" + +namespace leveldb { + +class SnapshotList; + +// Snapshots are kept in a doubly-linked list in the DB. +// Each SnapshotImpl corresponds to a particular sequence number. +class SnapshotImpl : public Snapshot { + public: + SequenceNumber number_; // const after creation + + private: + friend class SnapshotList; + + // SnapshotImpl is kept in a doubly-linked circular list + SnapshotImpl* prev_; + SnapshotImpl* next_; + + SnapshotList* list_; // just for sanity checks +}; + +class SnapshotList { + public: + SnapshotList() { + list_.prev_ = &list_; + list_.next_ = &list_; + } + + bool empty() const { return list_.next_ == &list_; } + SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } + SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } + + const SnapshotImpl* New(SequenceNumber seq) { + SnapshotImpl* s = new SnapshotImpl; + s->number_ = seq; + s->list_ = this; + s->next_ = &list_; + s->prev_ = list_.prev_; + s->prev_->next_ = s; + s->next_->prev_ = s; + return s; + } + + void Delete(const SnapshotImpl* s) { + assert(s->list_ == this); + s->prev_->next_ = s->next_; + s->next_->prev_ = s->prev_; + delete s; + } + + private: + // Dummy head of doubly-linked list of snapshots + SnapshotImpl list_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/src/leveldb/db/table_cache.cc b/src/leveldb/db/table_cache.cc new file mode 100644 index 0000000..497db27 --- /dev/null +++ b/src/leveldb/db/table_cache.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/table_cache.h" + +#include "db/filename.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/coding.h" + +namespace leveldb { + +struct TableAndFile { + RandomAccessFile* file; + Table* table; +}; + +static void DeleteEntry(const Slice& key, void* value) { + TableAndFile* tf = reinterpret_cast(value); + delete tf->table; + delete tf->file; + delete tf; +} + +static void UnrefEntry(void* arg1, void* arg2) { + Cache* cache = reinterpret_cast(arg1); + Cache::Handle* h = reinterpret_cast(arg2); + cache->Release(h); +} + +TableCache::TableCache(const std::string& dbname, + const Options* options, + int entries) + : env_(options->env), + dbname_(dbname), + options_(options), + cache_(NewLRUCache(entries)) { +} + +TableCache::~TableCache() { + delete cache_; +} + +Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, + Cache::Handle** handle) { + Status s; + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + Slice key(buf, sizeof(buf)); + *handle = cache_->Lookup(key); + if (*handle == NULL) { + std::string fname = TableFileName(dbname_, file_number); + RandomAccessFile* file = NULL; + Table* table = NULL; + s = env_->NewRandomAccessFile(fname, &file); + if (s.ok()) { + s = Table::Open(*options_, file, file_size, &table); + } + + if (!s.ok()) { + assert(table == NULL); + delete file; + // We do not cache error results so that if the error is transient, + // or somebody repairs the file, we recover automatically. + } else { + TableAndFile* tf = new TableAndFile; + tf->file = file; + tf->table = table; + *handle = cache_->Insert(key, tf, 1, &DeleteEntry); + } + } + return s; +} + +Iterator* TableCache::NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr) { + if (tableptr != NULL) { + *tableptr = NULL; + } + + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (!s.ok()) { + return NewErrorIterator(s); + } + + Table* table = reinterpret_cast(cache_->Value(handle))->table; + Iterator* result = table->NewIterator(options); + result->RegisterCleanup(&UnrefEntry, cache_, handle); + if (tableptr != NULL) { + *tableptr = table; + } + return result; +} + +Status TableCache::Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (s.ok()) { + Table* t = reinterpret_cast(cache_->Value(handle))->table; + s = t->InternalGet(options, k, arg, saver); + cache_->Release(handle); + } + return s; +} + +void TableCache::Evict(uint64_t file_number) { + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + cache_->Erase(Slice(buf, sizeof(buf))); +} + +} // namespace leveldb diff --git a/src/leveldb/db/table_cache.h b/src/leveldb/db/table_cache.h new file mode 100644 index 0000000..8cf4aaf --- /dev/null +++ b/src/leveldb/db/table_cache.h @@ -0,0 +1,61 @@ +// 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. +// +// Thread-safe (provides internal synchronization) + +#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ +#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ + +#include +#include +#include "db/dbformat.h" +#include "leveldb/cache.h" +#include "leveldb/table.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +class TableCache { + public: + TableCache(const std::string& dbname, const Options* options, int entries); + ~TableCache(); + + // Return an iterator for the specified file number (the corresponding + // file length must be exactly "file_size" bytes). If "tableptr" is + // non-NULL, also sets "*tableptr" to point to the Table object + // underlying the returned iterator, or NULL if no Table object underlies + // the returned iterator. The returned "*tableptr" object is owned by + // the cache and should not be deleted, and is valid for as long as the + // returned iterator is live. + Iterator* NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr = NULL); + + // If a seek to internal key "k" in specified file finds an entry, + // call (*handle_result)(arg, found_key, found_value). + Status Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*handle_result)(void*, const Slice&, const Slice&)); + + // Evict any entry for the specified file number + void Evict(uint64_t file_number); + + private: + Env* const env_; + const std::string dbname_; + const Options* options_; + Cache* cache_; + + Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/src/leveldb/db/version_edit.cc b/src/leveldb/db/version_edit.cc new file mode 100644 index 0000000..f10a2d5 --- /dev/null +++ b/src/leveldb/db/version_edit.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" + +#include "db/version_set.h" +#include "util/coding.h" + +namespace leveldb { + +// Tag numbers for serialized VersionEdit. These numbers are written to +// disk and should not be changed. +enum Tag { + kComparator = 1, + kLogNumber = 2, + kNextFileNumber = 3, + kLastSequence = 4, + kCompactPointer = 5, + kDeletedFile = 6, + kNewFile = 7, + // 8 was used for large value refs + kPrevLogNumber = 9 +}; + +void VersionEdit::Clear() { + comparator_.clear(); + log_number_ = 0; + prev_log_number_ = 0; + last_sequence_ = 0; + next_file_number_ = 0; + has_comparator_ = false; + has_log_number_ = false; + has_prev_log_number_ = false; + has_next_file_number_ = false; + has_last_sequence_ = false; + deleted_files_.clear(); + new_files_.clear(); +} + +void VersionEdit::EncodeTo(std::string* dst) const { + if (has_comparator_) { + PutVarint32(dst, kComparator); + PutLengthPrefixedSlice(dst, comparator_); + } + if (has_log_number_) { + PutVarint32(dst, kLogNumber); + PutVarint64(dst, log_number_); + } + if (has_prev_log_number_) { + PutVarint32(dst, kPrevLogNumber); + PutVarint64(dst, prev_log_number_); + } + if (has_next_file_number_) { + PutVarint32(dst, kNextFileNumber); + PutVarint64(dst, next_file_number_); + } + if (has_last_sequence_) { + PutVarint32(dst, kLastSequence); + PutVarint64(dst, last_sequence_); + } + + for (size_t i = 0; i < compact_pointers_.size(); i++) { + PutVarint32(dst, kCompactPointer); + PutVarint32(dst, compact_pointers_[i].first); // level + PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); + } + + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + PutVarint32(dst, kDeletedFile); + PutVarint32(dst, iter->first); // level + PutVarint64(dst, iter->second); // file number + } + + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + PutVarint32(dst, kNewFile); + PutVarint32(dst, new_files_[i].first); // level + PutVarint64(dst, f.number); + PutVarint64(dst, f.file_size); + PutLengthPrefixedSlice(dst, f.smallest.Encode()); + PutLengthPrefixedSlice(dst, f.largest.Encode()); + } +} + +static bool GetInternalKey(Slice* input, InternalKey* dst) { + Slice str; + if (GetLengthPrefixedSlice(input, &str)) { + dst->DecodeFrom(str); + return true; + } else { + return false; + } +} + +static bool GetLevel(Slice* input, int* level) { + uint32_t v; + if (GetVarint32(input, &v) && + v < config::kNumLevels) { + *level = v; + return true; + } else { + return false; + } +} + +Status VersionEdit::DecodeFrom(const Slice& src) { + Clear(); + Slice input = src; + const char* msg = NULL; + uint32_t tag; + + // Temporary storage for parsing + int level; + uint64_t number; + FileMetaData f; + Slice str; + InternalKey key; + + while (msg == NULL && GetVarint32(&input, &tag)) { + switch (tag) { + case kComparator: + if (GetLengthPrefixedSlice(&input, &str)) { + comparator_ = str.ToString(); + has_comparator_ = true; + } else { + msg = "comparator name"; + } + break; + + case kLogNumber: + if (GetVarint64(&input, &log_number_)) { + has_log_number_ = true; + } else { + msg = "log number"; + } + break; + + case kPrevLogNumber: + if (GetVarint64(&input, &prev_log_number_)) { + has_prev_log_number_ = true; + } else { + msg = "previous log number"; + } + break; + + case kNextFileNumber: + if (GetVarint64(&input, &next_file_number_)) { + has_next_file_number_ = true; + } else { + msg = "next file number"; + } + break; + + case kLastSequence: + if (GetVarint64(&input, &last_sequence_)) { + has_last_sequence_ = true; + } else { + msg = "last sequence number"; + } + break; + + case kCompactPointer: + if (GetLevel(&input, &level) && + GetInternalKey(&input, &key)) { + compact_pointers_.push_back(std::make_pair(level, key)); + } else { + msg = "compaction pointer"; + } + break; + + case kDeletedFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &number)) { + deleted_files_.insert(std::make_pair(level, number)); + } else { + msg = "deleted file"; + } + break; + + case kNewFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &f.number) && + GetVarint64(&input, &f.file_size) && + GetInternalKey(&input, &f.smallest) && + GetInternalKey(&input, &f.largest)) { + new_files_.push_back(std::make_pair(level, f)); + } else { + msg = "new-file entry"; + } + break; + + default: + msg = "unknown tag"; + break; + } + } + + if (msg == NULL && !input.empty()) { + msg = "invalid tag"; + } + + Status result; + if (msg != NULL) { + result = Status::Corruption("VersionEdit", msg); + } + return result; +} + +std::string VersionEdit::DebugString() const { + std::string r; + r.append("VersionEdit {"); + if (has_comparator_) { + r.append("\n Comparator: "); + r.append(comparator_); + } + if (has_log_number_) { + r.append("\n LogNumber: "); + AppendNumberTo(&r, log_number_); + } + if (has_prev_log_number_) { + r.append("\n PrevLogNumber: "); + AppendNumberTo(&r, prev_log_number_); + } + if (has_next_file_number_) { + r.append("\n NextFile: "); + AppendNumberTo(&r, next_file_number_); + } + if (has_last_sequence_) { + r.append("\n LastSeq: "); + AppendNumberTo(&r, last_sequence_); + } + for (size_t i = 0; i < compact_pointers_.size(); i++) { + r.append("\n CompactPointer: "); + AppendNumberTo(&r, compact_pointers_[i].first); + r.append(" "); + r.append(compact_pointers_[i].second.DebugString()); + } + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + r.append("\n DeleteFile: "); + AppendNumberTo(&r, iter->first); + r.append(" "); + AppendNumberTo(&r, iter->second); + } + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + r.append("\n AddFile: "); + AppendNumberTo(&r, new_files_[i].first); + r.append(" "); + AppendNumberTo(&r, f.number); + r.append(" "); + AppendNumberTo(&r, f.file_size); + r.append(" "); + r.append(f.smallest.DebugString()); + r.append(" .. "); + r.append(f.largest.DebugString()); + } + r.append("\n}\n"); + return r; +} + +} // namespace leveldb diff --git a/src/leveldb/db/version_edit.h b/src/leveldb/db/version_edit.h new file mode 100644 index 0000000..eaef77b --- /dev/null +++ b/src/leveldb/db/version_edit.h @@ -0,0 +1,107 @@ +// 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_VERSION_EDIT_H_ +#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ + +#include +#include +#include +#include "db/dbformat.h" + +namespace leveldb { + +class VersionSet; + +struct FileMetaData { + int refs; + int allowed_seeks; // Seeks allowed until compaction + uint64_t number; + uint64_t file_size; // File size in bytes + InternalKey smallest; // Smallest internal key served by table + InternalKey largest; // Largest internal key served by table + + FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { } +}; + +class VersionEdit { + public: + VersionEdit() { Clear(); } + ~VersionEdit() { } + + void Clear(); + + void SetComparatorName(const Slice& name) { + has_comparator_ = true; + comparator_ = name.ToString(); + } + void SetLogNumber(uint64_t num) { + has_log_number_ = true; + log_number_ = num; + } + void SetPrevLogNumber(uint64_t num) { + has_prev_log_number_ = true; + prev_log_number_ = num; + } + void SetNextFile(uint64_t num) { + has_next_file_number_ = true; + next_file_number_ = num; + } + void SetLastSequence(SequenceNumber seq) { + has_last_sequence_ = true; + last_sequence_ = seq; + } + void SetCompactPointer(int level, const InternalKey& key) { + compact_pointers_.push_back(std::make_pair(level, key)); + } + + // Add the specified file at the specified number. + // REQUIRES: This version has not been saved (see VersionSet::SaveTo) + // REQUIRES: "smallest" and "largest" are smallest and largest keys in file + void AddFile(int level, uint64_t file, + uint64_t file_size, + const InternalKey& smallest, + const InternalKey& largest) { + FileMetaData f; + f.number = file; + f.file_size = file_size; + f.smallest = smallest; + f.largest = largest; + new_files_.push_back(std::make_pair(level, f)); + } + + // Delete the specified "file" from the specified "level". + void DeleteFile(int level, uint64_t file) { + deleted_files_.insert(std::make_pair(level, file)); + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(const Slice& src); + + std::string DebugString() const; + + private: + friend class VersionSet; + + typedef std::set< std::pair > DeletedFileSet; + + std::string comparator_; + uint64_t log_number_; + uint64_t prev_log_number_; + uint64_t next_file_number_; + SequenceNumber last_sequence_; + bool has_comparator_; + bool has_log_number_; + bool has_prev_log_number_; + bool has_next_file_number_; + bool has_last_sequence_; + + std::vector< std::pair > compact_pointers_; + DeletedFileSet deleted_files_; + std::vector< std::pair > new_files_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/src/leveldb/db/version_edit_test.cc b/src/leveldb/db/version_edit_test.cc new file mode 100644 index 0000000..280310b --- /dev/null +++ b/src/leveldb/db/version_edit_test.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" +#include "util/testharness.h" + +namespace leveldb { + +static void TestEncodeDecode(const VersionEdit& edit) { + std::string encoded, encoded2; + edit.EncodeTo(&encoded); + VersionEdit parsed; + Status s = parsed.DecodeFrom(encoded); + ASSERT_TRUE(s.ok()) << s.ToString(); + parsed.EncodeTo(&encoded2); + ASSERT_EQ(encoded, encoded2); +} + +class VersionEditTest { }; + +TEST(VersionEditTest, EncodeDecode) { + static const uint64_t kBig = 1ull << 50; + + VersionEdit edit; + for (int i = 0; i < 4; i++) { + TestEncodeDecode(edit); + edit.AddFile(3, kBig + 300 + i, kBig + 400 + i, + InternalKey("foo", kBig + 500 + i, kTypeValue), + InternalKey("zoo", kBig + 600 + i, kTypeDeletion)); + edit.DeleteFile(4, kBig + 700 + i); + edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue)); + } + + edit.SetComparatorName("foo"); + edit.SetLogNumber(kBig + 100); + edit.SetNextFile(kBig + 200); + edit.SetLastSequence(kBig + 1000); + TestEncodeDecode(edit); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc new file mode 100644 index 0000000..66d73be --- /dev/null +++ b/src/leveldb/db/version_set.cc @@ -0,0 +1,1531 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" + +#include +#include +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "leveldb/env.h" +#include "leveldb/table_builder.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +static const int kTargetFileSize = 2 * 1048576; + +// Maximum bytes of overlaps in grandparent (i.e., level+2) before we +// stop building a single file in a level->level+1 compaction. +static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; + +// Maximum number of bytes in all compacted files. We avoid expanding +// the lower level file set of a compaction if it would make the +// total compaction cover more than this many bytes. +static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; + +static double MaxBytesForLevel(int level) { + // Note: the result for level zero is not really used since we set + // the level-0 compaction threshold based on number of files. + double result = 10 * 1048576.0; // Result for both level-0 and level-1 + while (level > 1) { + result *= 10; + level--; + } + return result; +} + +static uint64_t MaxFileSizeForLevel(int level) { + return kTargetFileSize; // We could vary per level to reduce number of files? +} + +static int64_t TotalFileSize(const std::vector& files) { + int64_t sum = 0; + for (size_t i = 0; i < files.size(); i++) { + sum += files[i]->file_size; + } + return sum; +} + +namespace { +std::string IntSetToString(const std::set& s) { + std::string result = "{"; + for (std::set::const_iterator it = s.begin(); + it != s.end(); + ++it) { + result += (result.size() > 1) ? "," : ""; + result += NumberToString(*it); + } + result += "}"; + return result; +} +} // namespace + +Version::~Version() { + assert(refs_ == 0); + + // Remove from linked list + prev_->next_ = next_; + next_->prev_ = prev_; + + // Drop references to files + for (int level = 0; level < config::kNumLevels; level++) { + for (size_t i = 0; i < files_[level].size(); i++) { + FileMetaData* f = files_[level][i]; + assert(f->refs > 0); + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } +} + +int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key) { + uint32_t left = 0; + uint32_t right = files.size(); + while (left < right) { + uint32_t mid = (left + right) / 2; + const FileMetaData* f = files[mid]; + if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { + // Key at "mid.largest" is < "target". Therefore all + // files at or before "mid" are uninteresting. + left = mid + 1; + } else { + // Key at "mid.largest" is >= "target". Therefore all files + // after "mid" are uninteresting. + right = mid; + } + } + return right; +} + +static bool AfterFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs before all keys and is therefore never after *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->largest.user_key()) > 0); +} + +static bool BeforeFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs after all keys and is therefore never before *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->smallest.user_key()) < 0); +} + +bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + const Comparator* ucmp = icmp.user_comparator(); + if (!disjoint_sorted_files) { + // Need to check against all files + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + if (AfterFile(ucmp, smallest_user_key, f) || + BeforeFile(ucmp, largest_user_key, f)) { + // No overlap + } else { + return true; // Overlap + } + } + return false; + } + + // Binary search over file list + uint32_t index = 0; + if (smallest_user_key != NULL) { + // Find the earliest possible internal key for smallest_user_key + InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); + index = FindFile(icmp, files, small.Encode()); + } + + if (index >= files.size()) { + // beginning of range is after all files, so no overlap. + return false; + } + + return !BeforeFile(ucmp, largest_user_key, files[index]); +} + +// An internal iterator. For a given version/level pair, yields +// information about the files in the level. For a given entry, key() +// is the largest key that occurs in the file, and value() is an +// 16-byte value containing the file number and file size, both +// encoded using EncodeFixed64. +class Version::LevelFileNumIterator : public Iterator { + public: + LevelFileNumIterator(const InternalKeyComparator& icmp, + const std::vector* flist) + : icmp_(icmp), + flist_(flist), + index_(flist->size()) { // Marks as invalid + } + virtual bool Valid() const { + return index_ < flist_->size(); + } + virtual void Seek(const Slice& target) { + index_ = FindFile(icmp_, *flist_, target); + } + virtual void SeekToFirst() { index_ = 0; } + virtual void SeekToLast() { + index_ = flist_->empty() ? 0 : flist_->size() - 1; + } + virtual void Next() { + assert(Valid()); + index_++; + } + virtual void Prev() { + assert(Valid()); + if (index_ == 0) { + index_ = flist_->size(); // Marks as invalid + } else { + index_--; + } + } + Slice key() const { + assert(Valid()); + return (*flist_)[index_]->largest.Encode(); + } + Slice value() const { + assert(Valid()); + EncodeFixed64(value_buf_, (*flist_)[index_]->number); + EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size); + return Slice(value_buf_, sizeof(value_buf_)); + } + virtual Status status() const { return Status::OK(); } + private: + const InternalKeyComparator icmp_; + const std::vector* const flist_; + uint32_t index_; + + // Backing store for value(). Holds the file number and size. + mutable char value_buf_[16]; +}; + +static Iterator* GetFileIterator(void* arg, + const ReadOptions& options, + const Slice& file_value) { + TableCache* cache = reinterpret_cast(arg); + if (file_value.size() != 16) { + return NewErrorIterator( + Status::Corruption("FileReader invoked with unexpected value")); + } else { + return cache->NewIterator(options, + DecodeFixed64(file_value.data()), + DecodeFixed64(file_value.data() + 8)); + } +} + +Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, + int level) const { + return NewTwoLevelIterator( + new LevelFileNumIterator(vset_->icmp_, &files_[level]), + &GetFileIterator, vset_->table_cache_, options); +} + +void Version::AddIterators(const ReadOptions& options, + std::vector* iters) { + // Merge all level zero files together since they may overlap + for (size_t i = 0; i < files_[0].size(); i++) { + iters->push_back( + vset_->table_cache_->NewIterator( + options, files_[0][i]->number, files_[0][i]->file_size)); + } + + // For levels > 0, we can use a concatenating iterator that sequentially + // walks through the non-overlapping files in the level, opening them + // lazily. + for (int level = 1; level < config::kNumLevels; level++) { + if (!files_[level].empty()) { + iters->push_back(NewConcatenatingIterator(options, level)); + } + } +} + +// Callback from TableCache::Get() +namespace { +enum SaverState { + kNotFound, + kFound, + kDeleted, + kCorrupt, +}; +struct Saver { + SaverState state; + const Comparator* ucmp; + Slice user_key; + std::string* value; +}; +} +static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { + Saver* s = reinterpret_cast(arg); + ParsedInternalKey parsed_key; + if (!ParseInternalKey(ikey, &parsed_key)) { + s->state = kCorrupt; + } else { + if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { + s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; + if (s->state == kFound) { + s->value->assign(v.data(), v.size()); + } + } + } +} + +static bool NewestFirst(FileMetaData* a, FileMetaData* b) { + return a->number > b->number; +} + +void Version::ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)) { + // TODO(sanjay): Change Version::Get() to use this function. + const Comparator* ucmp = vset_->icmp_.user_comparator(); + + // Search level-0 in order from newest to oldest. + std::vector tmp; + tmp.reserve(files_[0].size()); + for (uint32_t i = 0; i < files_[0].size(); i++) { + FileMetaData* f = files_[0][i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (!tmp.empty()) { + std::sort(tmp.begin(), tmp.end(), NewestFirst); + for (uint32_t i = 0; i < tmp.size(); i++) { + if (!(*func)(arg, 0, tmp[i])) { + return; + } + } + } + + // Search other levels. + for (int level = 1; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Binary search to find earliest index whose largest key >= internal_key. + uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key); + if (index < num_files) { + FileMetaData* f = files_[level][index]; + if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) { + // All of "f" is past any data for user_key + } else { + if (!(*func)(arg, level, f)) { + return; + } + } + } + } +} + +Status Version::Get(const ReadOptions& options, + const LookupKey& k, + std::string* value, + GetStats* stats) { + Slice ikey = k.internal_key(); + Slice user_key = k.user_key(); + const Comparator* ucmp = vset_->icmp_.user_comparator(); + Status s; + + stats->seek_file = NULL; + stats->seek_file_level = -1; + FileMetaData* last_file_read = NULL; + int last_file_read_level = -1; + + // We can search level-by-level since entries never hop across + // levels. Therefore we are guaranteed that if we find data + // in an smaller level, later levels are irrelevant. + std::vector tmp; + FileMetaData* tmp2; + for (int level = 0; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Get the list of files to search in this level + FileMetaData* const* files = &files_[level][0]; + if (level == 0) { + // Level-0 files may overlap each other. Find all files that + // overlap user_key and process them in order from newest to oldest. + tmp.reserve(num_files); + for (uint32_t i = 0; i < num_files; i++) { + FileMetaData* f = files[i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (tmp.empty()) continue; + + std::sort(tmp.begin(), tmp.end(), NewestFirst); + files = &tmp[0]; + num_files = tmp.size(); + } else { + // Binary search to find earliest index whose largest key >= ikey. + uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); + if (index >= num_files) { + files = NULL; + num_files = 0; + } else { + tmp2 = files[index]; + if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { + // All of "tmp2" is past any data for user_key + files = NULL; + num_files = 0; + } else { + files = &tmp2; + num_files = 1; + } + } + } + + for (uint32_t i = 0; i < num_files; ++i) { + if (last_file_read != NULL && stats->seek_file == NULL) { + // We have had more than one seek for this read. Charge the 1st file. + stats->seek_file = last_file_read; + stats->seek_file_level = last_file_read_level; + } + + FileMetaData* f = files[i]; + last_file_read = f; + last_file_read_level = level; + + Saver saver; + saver.state = kNotFound; + saver.ucmp = ucmp; + saver.user_key = user_key; + saver.value = value; + s = vset_->table_cache_->Get(options, f->number, f->file_size, + ikey, &saver, SaveValue); + if (!s.ok()) { + return s; + } + switch (saver.state) { + case kNotFound: + break; // Keep searching in other files + case kFound: + return s; + case kDeleted: + s = Status::NotFound(Slice()); // Use empty error message for speed + return s; + case kCorrupt: + s = Status::Corruption("corrupted key for ", user_key); + return s; + } + } + } + + return Status::NotFound(Slice()); // Use an empty error message for speed +} + +bool Version::UpdateStats(const GetStats& stats) { + FileMetaData* f = stats.seek_file; + if (f != NULL) { + f->allowed_seeks--; + if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) { + file_to_compact_ = f; + file_to_compact_level_ = stats.seek_file_level; + return true; + } + } + return false; +} + +bool Version::RecordReadSample(Slice internal_key) { + ParsedInternalKey ikey; + if (!ParseInternalKey(internal_key, &ikey)) { + return false; + } + + struct State { + GetStats stats; // Holds first matching file + int matches; + + static bool Match(void* arg, int level, FileMetaData* f) { + State* state = reinterpret_cast(arg); + state->matches++; + if (state->matches == 1) { + // Remember first match. + state->stats.seek_file = f; + state->stats.seek_file_level = level; + } + // We can stop iterating once we have a second match. + return state->matches < 2; + } + }; + + State state; + state.matches = 0; + ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match); + + // Must have at least two matches since we want to merge across + // files. But what if we have a single file that contains many + // overwrites and deletions? Should we have another mechanism for + // finding such files? + if (state.matches >= 2) { + // 1MB cost is about 1 seek (see comment in Builder::Apply). + return UpdateStats(state.stats); + } + return false; +} + +void Version::Ref() { + ++refs_; +} + +void Version::Unref() { + assert(this != &vset_->dummy_versions_); + assert(refs_ >= 1); + --refs_; + if (refs_ == 0) { + delete this; + } +} + +bool Version::OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], + smallest_user_key, largest_user_key); +} + +int Version::PickLevelForMemTableOutput( + const Slice& smallest_user_key, + const Slice& largest_user_key) { + int level = 0; + if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { + // Push to next level if there is no overlap in next level, + // and the #bytes overlapping in the level after that are limited. + InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey limit(largest_user_key, 0, static_cast(0)); + std::vector overlaps; + while (level < config::kMaxMemCompactLevel) { + if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { + break; + } + if (level + 2 < config::kNumLevels) { + // Check that file does not overlap too many grandparent bytes. + GetOverlappingInputs(level + 2, &start, &limit, &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > kMaxGrandParentOverlapBytes) { + break; + } + } + level++; + } + } + return level; +} + +// Store in "*inputs" all files in "level" that overlap [begin,end] +void Version::GetOverlappingInputs( + int level, + const InternalKey* begin, + const InternalKey* end, + std::vector* inputs) { + assert(level >= 0); + assert(level < config::kNumLevels); + inputs->clear(); + Slice user_begin, user_end; + if (begin != NULL) { + user_begin = begin->user_key(); + } + if (end != NULL) { + user_end = end->user_key(); + } + const Comparator* user_cmp = vset_->icmp_.user_comparator(); + for (size_t i = 0; i < files_[level].size(); ) { + FileMetaData* f = files_[level][i++]; + const Slice file_start = f->smallest.user_key(); + const Slice file_limit = f->largest.user_key(); + if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) { + // "f" is completely before specified range; skip it + } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) { + // "f" is completely after specified range; skip it + } else { + inputs->push_back(f); + if (level == 0) { + // Level-0 files may overlap each other. So check if the newly + // added file has expanded the range. If so, restart search. + if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) { + user_begin = file_start; + inputs->clear(); + i = 0; + } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) { + user_end = file_limit; + inputs->clear(); + i = 0; + } + } + } + } +} + +std::string Version::DebugString() const { + std::string r; + for (int level = 0; level < config::kNumLevels; level++) { + // E.g., + // --- level 1 --- + // 17:123['a' .. 'd'] + // 20:43['e' .. 'g'] + r.append("--- level "); + AppendNumberTo(&r, level); + r.append(" ---\n"); + const std::vector& files = files_[level]; + for (size_t i = 0; i < files.size(); i++) { + r.push_back(' '); + AppendNumberTo(&r, files[i]->number); + r.push_back(':'); + AppendNumberTo(&r, files[i]->file_size); + r.append("["); + r.append(files[i]->smallest.DebugString()); + r.append(" .. "); + r.append(files[i]->largest.DebugString()); + r.append("]\n"); + } + } + return r; +} + +// A helper class so we can efficiently apply a whole sequence +// of edits to a particular state without creating intermediate +// Versions that contain full copies of the intermediate state. +class VersionSet::Builder { + private: + // Helper to sort by v->files_[file_number].smallest + struct BySmallestKey { + const InternalKeyComparator* internal_comparator; + + bool operator()(FileMetaData* f1, FileMetaData* f2) const { + int r = internal_comparator->Compare(f1->smallest, f2->smallest); + if (r != 0) { + return (r < 0); + } else { + // Break ties by file number + return (f1->number < f2->number); + } + } + }; + + typedef std::set FileSet; + struct LevelState { + std::set deleted_files; + FileSet* added_files; + }; + + VersionSet* vset_; + Version* base_; + LevelState levels_[config::kNumLevels]; + + public: + // Initialize a builder with the files from *base and other info from *vset + Builder(VersionSet* vset, Version* base) + : vset_(vset), + base_(base) { + base_->Ref(); + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + levels_[level].added_files = new FileSet(cmp); + } + } + + ~Builder() { + for (int level = 0; level < config::kNumLevels; level++) { + const FileSet* added = levels_[level].added_files; + std::vector to_unref; + to_unref.reserve(added->size()); + for (FileSet::const_iterator it = added->begin(); + it != added->end(); ++it) { + to_unref.push_back(*it); + } + delete added; + for (uint32_t i = 0; i < to_unref.size(); i++) { + FileMetaData* f = to_unref[i]; + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } + base_->Unref(); + } + + // Apply all of the edits in *edit to the current state. + void Apply(VersionEdit* edit) { + // Update compaction pointers + for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { + const int level = edit->compact_pointers_[i].first; + vset_->compact_pointer_[level] = + edit->compact_pointers_[i].second.Encode().ToString(); + } + + // Delete files + const VersionEdit::DeletedFileSet& del = edit->deleted_files_; + for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); + iter != del.end(); + ++iter) { + const int level = iter->first; + const uint64_t number = iter->second; + levels_[level].deleted_files.insert(number); + } + + // Add new files + for (size_t i = 0; i < edit->new_files_.size(); i++) { + const int level = edit->new_files_[i].first; + FileMetaData* f = new FileMetaData(edit->new_files_[i].second); + f->refs = 1; + + // We arrange to automatically compact this file after + // a certain number of seeks. Let's assume: + // (1) One seek costs 10ms + // (2) Writing or reading 1MB costs 10ms (100MB/s) + // (3) A compaction of 1MB does 25MB of IO: + // 1MB read from this level + // 10-12MB read from next level (boundaries may be misaligned) + // 10-12MB written to next level + // This implies that 25 seeks cost the same as the compaction + // of 1MB of data. I.e., one seek costs approximately the + // same as the compaction of 40KB of data. We are a little + // conservative and allow approximately one seek for every 16KB + // of data before triggering a compaction. + f->allowed_seeks = (f->file_size / 16384); + if (f->allowed_seeks < 100) f->allowed_seeks = 100; + + levels_[level].deleted_files.erase(f->number); + levels_[level].added_files->insert(f); + } + } + + // Save the current state in *v. + void SaveTo(Version* v) { + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + // Merge the set of added files with the set of pre-existing files. + // Drop any deleted files. Store the result in *v. + const std::vector& base_files = base_->files_[level]; + std::vector::const_iterator base_iter = base_files.begin(); + std::vector::const_iterator base_end = base_files.end(); + const FileSet* added = levels_[level].added_files; + v->files_[level].reserve(base_files.size() + added->size()); + for (FileSet::const_iterator added_iter = added->begin(); + added_iter != added->end(); + ++added_iter) { + // Add all smaller files listed in base_ + for (std::vector::const_iterator bpos + = std::upper_bound(base_iter, base_end, *added_iter, cmp); + base_iter != bpos; + ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + + MaybeAddFile(v, level, *added_iter); + } + + // Add remaining base files + for (; base_iter != base_end; ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + +#ifndef NDEBUG + // Make sure there is no overlap in levels > 0 + if (level > 0) { + for (uint32_t i = 1; i < v->files_[level].size(); i++) { + const InternalKey& prev_end = v->files_[level][i-1]->largest; + const InternalKey& this_begin = v->files_[level][i]->smallest; + if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { + fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", + prev_end.DebugString().c_str(), + this_begin.DebugString().c_str()); + abort(); + } + } + } +#endif + } + } + + void MaybeAddFile(Version* v, int level, FileMetaData* f) { + if (levels_[level].deleted_files.count(f->number) > 0) { + // File is deleted: do nothing + } else { + std::vector* files = &v->files_[level]; + if (level > 0 && !files->empty()) { + // Must not overlap + assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest, + f->smallest) < 0); + } + f->refs++; + files->push_back(f); + } + } +}; + +VersionSet::VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator* cmp) + : env_(options->env), + dbname_(dbname), + options_(options), + table_cache_(table_cache), + icmp_(*cmp), + next_file_number_(2), + manifest_file_number_(0), // Filled by Recover() + last_sequence_(0), + log_number_(0), + prev_log_number_(0), + descriptor_file_(NULL), + descriptor_log_(NULL), + dummy_versions_(this), + current_(NULL) { + AppendVersion(new Version(this)); +} + +VersionSet::~VersionSet() { + current_->Unref(); + assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty + delete descriptor_log_; + delete descriptor_file_; +} + +void VersionSet::AppendVersion(Version* v) { + // Make "v" current + assert(v->refs_ == 0); + assert(v != current_); + if (current_ != NULL) { + current_->Unref(); + } + current_ = v; + v->Ref(); + + // Append to linked list + v->prev_ = dummy_versions_.prev_; + v->next_ = &dummy_versions_; + v->prev_->next_ = v; + v->next_->prev_ = v; +} + +Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { + if (edit->has_log_number_) { + assert(edit->log_number_ >= log_number_); + assert(edit->log_number_ < next_file_number_); + } else { + edit->SetLogNumber(log_number_); + } + + if (!edit->has_prev_log_number_) { + edit->SetPrevLogNumber(prev_log_number_); + } + + edit->SetNextFile(next_file_number_); + edit->SetLastSequence(last_sequence_); + + Version* v = new Version(this); + { + Builder builder(this, current_); + builder.Apply(edit); + builder.SaveTo(v); + } + Finalize(v); + + // Initialize new descriptor log file if necessary by creating + // a temporary file that contains a snapshot of the current version. + std::string new_manifest_file; + Status s; + if (descriptor_log_ == NULL) { + // No reason to unlock *mu here since we only hit this path in the + // first call to LogAndApply (when opening the database). + assert(descriptor_file_ == NULL); + new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); + edit->SetNextFile(next_file_number_); + s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); + if (s.ok()) { + descriptor_log_ = new log::Writer(descriptor_file_); + s = WriteSnapshot(descriptor_log_); + } + } + + // Unlock during expensive MANIFEST log write + { + mu->Unlock(); + + // Write new record to MANIFEST log + if (s.ok()) { + std::string record; + edit->EncodeTo(&record); + s = descriptor_log_->AddRecord(record); + if (s.ok()) { + s = descriptor_file_->Sync(); + } + if (!s.ok()) { + Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); + if (ManifestContains(record)) { + Log(options_->info_log, + "MANIFEST contains log record despite error; advancing to new " + "version to prevent mismatch between in-memory and logged state"); + s = Status::OK(); + } + } + } + + // If we just created a new descriptor file, install it by writing a + // new CURRENT file that points to it. + if (s.ok() && !new_manifest_file.empty()) { + s = SetCurrentFile(env_, dbname_, manifest_file_number_); + // No need to double-check MANIFEST in case of error since it + // will be discarded below. + } + + mu->Lock(); + } + + // Install the new version + if (s.ok()) { + AppendVersion(v); + log_number_ = edit->log_number_; + prev_log_number_ = edit->prev_log_number_; + } else { + delete v; + if (!new_manifest_file.empty()) { + delete descriptor_log_; + delete descriptor_file_; + descriptor_log_ = NULL; + descriptor_file_ = NULL; + env_->DeleteFile(new_manifest_file); + } + } + + return s; +} + +Status VersionSet::Recover() { + struct LogReporter : public log::Reader::Reporter { + Status* status; + virtual void Corruption(size_t bytes, const Status& s) { + if (this->status->ok()) *this->status = s; + } + }; + + // Read "CURRENT" file, which contains a pointer to the current manifest file + std::string current; + Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); + if (!s.ok()) { + return s; + } + if (current.empty() || current[current.size()-1] != '\n') { + return Status::Corruption("CURRENT file does not end with newline"); + } + current.resize(current.size() - 1); + + std::string dscname = dbname_ + "/" + current; + SequentialFile* file; + s = env_->NewSequentialFile(dscname, &file); + if (!s.ok()) { + return s; + } + + bool have_log_number = false; + bool have_prev_log_number = false; + bool have_next_file = false; + bool have_last_sequence = false; + uint64_t next_file = 0; + uint64_t last_sequence = 0; + uint64_t log_number = 0; + uint64_t prev_log_number = 0; + Builder builder(this, current_); + + { + LogReporter reporter; + reporter.status = &s; + log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch) && s.ok()) { + VersionEdit edit; + s = edit.DecodeFrom(record); + if (s.ok()) { + if (edit.has_comparator_ && + edit.comparator_ != icmp_.user_comparator()->Name()) { + s = Status::InvalidArgument( + edit.comparator_ + " does not match existing comparator ", + icmp_.user_comparator()->Name()); + } + } + + if (s.ok()) { + builder.Apply(&edit); + } + + if (edit.has_log_number_) { + log_number = edit.log_number_; + have_log_number = true; + } + + if (edit.has_prev_log_number_) { + prev_log_number = edit.prev_log_number_; + have_prev_log_number = true; + } + + if (edit.has_next_file_number_) { + next_file = edit.next_file_number_; + have_next_file = true; + } + + if (edit.has_last_sequence_) { + last_sequence = edit.last_sequence_; + have_last_sequence = true; + } + } + } + delete file; + file = NULL; + + if (s.ok()) { + if (!have_next_file) { + s = Status::Corruption("no meta-nextfile entry in descriptor"); + } else if (!have_log_number) { + s = Status::Corruption("no meta-lognumber entry in descriptor"); + } else if (!have_last_sequence) { + s = Status::Corruption("no last-sequence-number entry in descriptor"); + } + + if (!have_prev_log_number) { + prev_log_number = 0; + } + + MarkFileNumberUsed(prev_log_number); + MarkFileNumberUsed(log_number); + } + + if (s.ok()) { + Version* v = new Version(this); + builder.SaveTo(v); + // Install recovered version + Finalize(v); + AppendVersion(v); + manifest_file_number_ = next_file; + next_file_number_ = next_file + 1; + last_sequence_ = last_sequence; + log_number_ = log_number; + prev_log_number_ = prev_log_number; + } + + return s; +} + +void VersionSet::MarkFileNumberUsed(uint64_t number) { + if (next_file_number_ <= number) { + next_file_number_ = number + 1; + } +} + +void VersionSet::Finalize(Version* v) { + // Precomputed best level for next compaction + int best_level = -1; + double best_score = -1; + + for (int level = 0; level < config::kNumLevels-1; level++) { + double score; + if (level == 0) { + // We treat level-0 specially by bounding the number of files + // instead of number of bytes for two reasons: + // + // (1) With larger write-buffer sizes, it is nice not to do too + // many level-0 compactions. + // + // (2) The files in level-0 are merged on every read and + // therefore we wish to avoid too many files when the individual + // file size is small (perhaps because of a small write-buffer + // setting, or very high compression ratios, or lots of + // overwrites/deletions). + score = v->files_[level].size() / + static_cast(config::kL0_CompactionTrigger); + } else { + // Compute the ratio of current size to size limit. + const uint64_t level_bytes = TotalFileSize(v->files_[level]); + score = static_cast(level_bytes) / MaxBytesForLevel(level); + } + + if (score > best_score) { + best_level = level; + best_score = score; + } + } + + v->compaction_level_ = best_level; + v->compaction_score_ = best_score; +} + +Status VersionSet::WriteSnapshot(log::Writer* log) { + // TODO: Break up into multiple records to reduce memory usage on recovery? + + // Save metadata + VersionEdit edit; + edit.SetComparatorName(icmp_.user_comparator()->Name()); + + // Save compaction pointers + for (int level = 0; level < config::kNumLevels; level++) { + if (!compact_pointer_[level].empty()) { + InternalKey key; + key.DecodeFrom(compact_pointer_[level]); + edit.SetCompactPointer(level, key); + } + } + + // Save files + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = current_->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); + } + } + + std::string record; + edit.EncodeTo(&record); + return log->AddRecord(record); +} + +int VersionSet::NumLevelFiles(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return current_->files_[level].size(); +} + +const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { + // Update code if kNumLevels changes + assert(config::kNumLevels == 7); + snprintf(scratch->buffer, sizeof(scratch->buffer), + "files[ %d %d %d %d %d %d %d ]", + int(current_->files_[0].size()), + int(current_->files_[1].size()), + int(current_->files_[2].size()), + int(current_->files_[3].size()), + int(current_->files_[4].size()), + int(current_->files_[5].size()), + int(current_->files_[6].size())); + return scratch->buffer; +} + +// Return true iff the manifest contains the specified record. +bool VersionSet::ManifestContains(const std::string& record) const { + std::string fname = DescriptorFileName(dbname_, manifest_file_number_); + Log(options_->info_log, "ManifestContains: checking %s\n", fname.c_str()); + SequentialFile* file = NULL; + Status s = env_->NewSequentialFile(fname, &file); + if (!s.ok()) { + Log(options_->info_log, "ManifestContains: %s\n", s.ToString().c_str()); + return false; + } + log::Reader reader(file, NULL, true/*checksum*/, 0); + Slice r; + std::string scratch; + bool result = false; + while (reader.ReadRecord(&r, &scratch)) { + if (r == Slice(record)) { + result = true; + break; + } + } + delete file; + Log(options_->info_log, "ManifestContains: result = %d\n", result ? 1 : 0); + return result; +} + +uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { + uint64_t result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + if (icmp_.Compare(files[i]->largest, ikey) <= 0) { + // Entire file is before "ikey", so just add the file size + result += files[i]->file_size; + } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { + // Entire file is after "ikey", so ignore + if (level > 0) { + // Files other than level 0 are sorted by meta->smallest, so + // no further files in this level will contain data for + // "ikey". + break; + } + } else { + // "ikey" falls in the range for this table. Add the + // approximate offset of "ikey" within the table. + Table* tableptr; + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); + if (tableptr != NULL) { + result += tableptr->ApproximateOffsetOf(ikey.Encode()); + } + delete iter; + } + } + } + return result; +} + +void VersionSet::AddLiveFiles(std::set* live) { + for (Version* v = dummy_versions_.next_; + v != &dummy_versions_; + v = v->next_) { + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + live->insert(files[i]->number); + } + } + } +} + +int64_t VersionSet::NumLevelBytes(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return TotalFileSize(current_->files_[level]); +} + +int64_t VersionSet::MaxNextLevelOverlappingBytes() { + int64_t result = 0; + std::vector overlaps; + for (int level = 1; level < config::kNumLevels - 1; level++) { + for (size_t i = 0; i < current_->files_[level].size(); i++) { + const FileMetaData* f = current_->files_[level][i]; + current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest, + &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > result) { + result = sum; + } + } + } + return result; +} + +// Stores the minimal range that covers all entries in inputs in +// *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest) { + assert(!inputs.empty()); + smallest->Clear(); + largest->Clear(); + for (size_t i = 0; i < inputs.size(); i++) { + FileMetaData* f = inputs[i]; + if (i == 0) { + *smallest = f->smallest; + *largest = f->largest; + } else { + if (icmp_.Compare(f->smallest, *smallest) < 0) { + *smallest = f->smallest; + } + if (icmp_.Compare(f->largest, *largest) > 0) { + *largest = f->largest; + } + } + } +} + +// Stores the minimal range that covers all entries in inputs1 and inputs2 +// in *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest) { + std::vector all = inputs1; + all.insert(all.end(), inputs2.begin(), inputs2.end()); + GetRange(all, smallest, largest); +} + +Iterator* VersionSet::MakeInputIterator(Compaction* c) { + ReadOptions options; + options.verify_checksums = options_->paranoid_checks; + options.fill_cache = false; + + // Level-0 files have to be merged together. For other levels, + // we will make a concatenating iterator per level. + // TODO(opt): use concatenating iterator for level-0 if there is no overlap + const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); + Iterator** list = new Iterator*[space]; + int num = 0; + for (int which = 0; which < 2; which++) { + if (!c->inputs_[which].empty()) { + if (c->level() + which == 0) { + const std::vector& files = c->inputs_[which]; + for (size_t i = 0; i < files.size(); i++) { + list[num++] = table_cache_->NewIterator( + options, files[i]->number, files[i]->file_size); + } + } else { + // Create concatenating iterator for the files from this level + list[num++] = NewTwoLevelIterator( + new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), + &GetFileIterator, table_cache_, options); + } + } + } + assert(num <= space); + Iterator* result = NewMergingIterator(&icmp_, list, num); + delete[] list; + return result; +} + +Compaction* VersionSet::PickCompaction() { + Compaction* c; + int level; + + // We prefer compactions triggered by too much data in a level over + // the compactions triggered by seeks. + const bool size_compaction = (current_->compaction_score_ >= 1); + const bool seek_compaction = (current_->file_to_compact_ != NULL); + if (size_compaction) { + level = current_->compaction_level_; + assert(level >= 0); + assert(level+1 < config::kNumLevels); + c = new Compaction(level); + + // Pick the first file that comes after compact_pointer_[level] + for (size_t i = 0; i < current_->files_[level].size(); i++) { + FileMetaData* f = current_->files_[level][i]; + if (compact_pointer_[level].empty() || + icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { + c->inputs_[0].push_back(f); + break; + } + } + if (c->inputs_[0].empty()) { + // Wrap-around to the beginning of the key space + c->inputs_[0].push_back(current_->files_[level][0]); + } + } else if (seek_compaction) { + level = current_->file_to_compact_level_; + c = new Compaction(level); + c->inputs_[0].push_back(current_->file_to_compact_); + } else { + return NULL; + } + + c->input_version_ = current_; + c->input_version_->Ref(); + + // Files in level 0 may overlap each other, so pick up all overlapping ones + if (level == 0) { + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + // Note that the next call will discard the file we placed in + // c->inputs_[0] earlier and replace it with an overlapping set + // which will include the picked file. + current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); + assert(!c->inputs_[0].empty()); + } + + SetupOtherInputs(c); + + return c; +} + +void VersionSet::SetupOtherInputs(Compaction* c) { + const int level = c->level(); + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + + current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]); + + // Get entire range covered by compaction + InternalKey all_start, all_limit; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + + // See if we can grow the number of inputs in "level" without + // changing the number of "level+1" files we pick up. + if (!c->inputs_[1].empty()) { + std::vector expanded0; + current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); + const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); + const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); + const int64_t expanded0_size = TotalFileSize(expanded0); + if (expanded0.size() > c->inputs_[0].size() && + inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { + InternalKey new_start, new_limit; + GetRange(expanded0, &new_start, &new_limit); + std::vector expanded1; + current_->GetOverlappingInputs(level+1, &new_start, &new_limit, + &expanded1); + if (expanded1.size() == c->inputs_[1].size()) { + Log(options_->info_log, + "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", + level, + int(c->inputs_[0].size()), + int(c->inputs_[1].size()), + long(inputs0_size), long(inputs1_size), + int(expanded0.size()), + int(expanded1.size()), + long(expanded0_size), long(inputs1_size)); + smallest = new_start; + largest = new_limit; + c->inputs_[0] = expanded0; + c->inputs_[1] = expanded1; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + } + } + } + + // Compute the set of grandparent files that overlap this compaction + // (parent == level+1; grandparent == level+2) + if (level + 2 < config::kNumLevels) { + current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, + &c->grandparents_); + } + + if (false) { + Log(options_->info_log, "Compacting %d '%s' .. '%s'", + level, + smallest.DebugString().c_str(), + largest.DebugString().c_str()); + } + + // Update the place where we will do the next compaction for this level. + // We update this immediately instead of waiting for the VersionEdit + // to be applied so that if the compaction fails, we will try a different + // key range next time. + compact_pointer_[level] = largest.Encode().ToString(); + c->edit_.SetCompactPointer(level, largest); +} + +Compaction* VersionSet::CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end) { + std::vector inputs; + current_->GetOverlappingInputs(level, begin, end, &inputs); + if (inputs.empty()) { + return NULL; + } + + // Avoid compacting too much in one shot in case the range is large. + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if (level > 0) { + const uint64_t limit = MaxFileSizeForLevel(level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } + } + } + + Compaction* c = new Compaction(level); + c->input_version_ = current_; + c->input_version_->Ref(); + c->inputs_[0] = inputs; + SetupOtherInputs(c); + return c; +} + +Compaction::Compaction(int level) + : level_(level), + max_output_file_size_(MaxFileSizeForLevel(level)), + input_version_(NULL), + grandparent_index_(0), + seen_key_(false), + overlapped_bytes_(0) { + for (int i = 0; i < config::kNumLevels; i++) { + level_ptrs_[i] = 0; + } +} + +Compaction::~Compaction() { + if (input_version_ != NULL) { + input_version_->Unref(); + } +} + +bool Compaction::IsTrivialMove() const { + // Avoid a move if there is lots of overlapping grandparent data. + // Otherwise, the move could create a parent file that will require + // a very expensive merge later on. + return (num_input_files(0) == 1 && + num_input_files(1) == 0 && + TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); +} + +void Compaction::AddInputDeletions(VersionEdit* edit) { + for (int which = 0; which < 2; which++) { + for (size_t i = 0; i < inputs_[which].size(); i++) { + edit->DeleteFile(level_ + which, inputs_[which][i]->number); + } + } +} + +bool Compaction::IsBaseLevelForKey(const Slice& user_key) { + // Maybe use binary search to find right entry instead of linear search? + const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); + for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { + const std::vector& files = input_version_->files_[lvl]; + for (; level_ptrs_[lvl] < files.size(); ) { + FileMetaData* f = files[level_ptrs_[lvl]]; + if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { + // We've advanced far enough + if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { + // Key falls in this file's range, so definitely not base level + return false; + } + break; + } + level_ptrs_[lvl]++; + } + } + return true; +} + +bool Compaction::ShouldStopBefore(const Slice& internal_key) { + // Scan to find earliest grandparent file that contains key. + const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; + while (grandparent_index_ < grandparents_.size() && + icmp->Compare(internal_key, + grandparents_[grandparent_index_]->largest.Encode()) > 0) { + if (seen_key_) { + overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; + } + grandparent_index_++; + } + seen_key_ = true; + + if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { + // Too much overlap for current output; start new output + overlapped_bytes_ = 0; + return true; + } else { + return false; + } +} + +void Compaction::ReleaseInputs() { + if (input_version_ != NULL) { + input_version_->Unref(); + input_version_ = NULL; + } +} + +} // namespace leveldb diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h new file mode 100644 index 0000000..20de0e2 --- /dev/null +++ b/src/leveldb/db/version_set.h @@ -0,0 +1,398 @@ +// 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. +// +// The representation of a DBImpl consists of a set of Versions. The +// newest version is called "current". Older versions may be kept +// around to provide a consistent view to live iterators. +// +// Each Version keeps track of a set of Table files per level. The +// entire set of versions is maintained in a VersionSet. +// +// Version,VersionSet are thread-compatible, but require external +// synchronization on all accesses. + +#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ +#define STORAGE_LEVELDB_DB_VERSION_SET_H_ + +#include +#include +#include +#include "db/dbformat.h" +#include "db/version_edit.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +namespace log { class Writer; } + +class Compaction; +class Iterator; +class MemTable; +class TableBuilder; +class TableCache; +class Version; +class VersionSet; +class WritableFile; + +// Return the smallest index i such that files[i]->largest >= key. +// Return files.size() if there is no such file. +// REQUIRES: "files" contains a sorted list of non-overlapping files. +extern int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key); + +// Returns true iff some file in "files" overlaps the user key range +// [*smallest,*largest]. +// smallest==NULL represents a key smaller than all keys in the DB. +// largest==NULL represents a key largest than all keys in the DB. +// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges +// in sorted order. +extern bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key); + +class Version { + public: + // Append to *iters a sequence of iterators that will + // yield the contents of this Version when merged together. + // REQUIRES: This version has been saved (see VersionSet::SaveTo) + void AddIterators(const ReadOptions&, std::vector* iters); + + // Lookup the value for key. If found, store it in *val and + // return OK. Else return a non-OK status. Fills *stats. + // REQUIRES: lock is not held + struct GetStats { + FileMetaData* seek_file; + int seek_file_level; + }; + Status Get(const ReadOptions&, const LookupKey& key, std::string* val, + GetStats* stats); + + // Adds "stats" into the current state. Returns true if a new + // compaction may need to be triggered, false otherwise. + // REQUIRES: lock is held + bool UpdateStats(const GetStats& stats); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. Returns true if a new compaction may need to be triggered. + // REQUIRES: lock is held + bool RecordReadSample(Slice key); + + // Reference count management (so Versions do not disappear out from + // under live iterators) + void Ref(); + void Unref(); + + void GetOverlappingInputs( + int level, + const InternalKey* begin, // NULL means before all keys + const InternalKey* end, // NULL means after all keys + std::vector* inputs); + + // Returns true iff some file in the specified level overlaps + // some part of [*smallest_user_key,*largest_user_key]. + // smallest_user_key==NULL represents a key smaller than all keys in the DB. + // largest_user_key==NULL represents a key largest than all keys in the DB. + bool OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key); + + // Return the level at which we should place a new memtable compaction + // result that covers the range [smallest_user_key,largest_user_key]. + int PickLevelForMemTableOutput(const Slice& smallest_user_key, + const Slice& largest_user_key); + + int NumFiles(int level) const { return files_[level].size(); } + + // Return a human readable string that describes this version's contents. + std::string DebugString() const; + + private: + friend class Compaction; + friend class VersionSet; + + class LevelFileNumIterator; + Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; + + // Call func(arg, level, f) for every file that overlaps user_key in + // order from newest to oldest. If an invocation of func returns + // false, makes no more calls. + // + // REQUIRES: user portion of internal_key == user_key. + void ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)); + + VersionSet* vset_; // VersionSet to which this Version belongs + Version* next_; // Next version in linked list + Version* prev_; // Previous version in linked list + int refs_; // Number of live refs to this version + + // List of files per level + std::vector files_[config::kNumLevels]; + + // Next file to compact based on seek stats. + FileMetaData* file_to_compact_; + int file_to_compact_level_; + + // Level that should be compacted next and its compaction score. + // Score < 1 means compaction is not strictly needed. These fields + // are initialized by Finalize(). + double compaction_score_; + int compaction_level_; + + explicit Version(VersionSet* vset) + : vset_(vset), next_(this), prev_(this), refs_(0), + file_to_compact_(NULL), + file_to_compact_level_(-1), + compaction_score_(-1), + compaction_level_(-1) { + } + + ~Version(); + + // No copying allowed + Version(const Version&); + void operator=(const Version&); +}; + +class VersionSet { + public: + VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator*); + ~VersionSet(); + + // Apply *edit to the current version to form a new descriptor that + // is both saved to persistent state and installed as the new + // current version. Will release *mu while actually writing to the file. + // REQUIRES: *mu is held on entry. + // REQUIRES: no other thread concurrently calls LogAndApply() + Status LogAndApply(VersionEdit* edit, port::Mutex* mu) + EXCLUSIVE_LOCKS_REQUIRED(mu); + + // Recover the last saved descriptor from persistent storage. + Status Recover(); + + // Return the current version. + Version* current() const { return current_; } + + // Return the current manifest file number + uint64_t ManifestFileNumber() const { return manifest_file_number_; } + + // Allocate and return a new file number + uint64_t NewFileNumber() { return next_file_number_++; } + + // Arrange to reuse "file_number" unless a newer file number has + // already been allocated. + // REQUIRES: "file_number" was returned by a call to NewFileNumber(). + void ReuseFileNumber(uint64_t file_number) { + if (next_file_number_ == file_number + 1) { + next_file_number_ = file_number; + } + } + + // Return the number of Table files at the specified level. + int NumLevelFiles(int level) const; + + // Return the combined file size of all files at the specified level. + int64_t NumLevelBytes(int level) const; + + // Return the last sequence number. + uint64_t LastSequence() const { return last_sequence_; } + + // Set the last sequence number to s. + void SetLastSequence(uint64_t s) { + assert(s >= last_sequence_); + last_sequence_ = s; + } + + // Mark the specified file number as used. + void MarkFileNumberUsed(uint64_t number); + + // Return the current log file number. + uint64_t LogNumber() const { return log_number_; } + + // Return the log file number for the log file that is currently + // being compacted, or zero if there is no such log file. + uint64_t PrevLogNumber() const { return prev_log_number_; } + + // Pick level and inputs for a new compaction. + // Returns NULL if there is no compaction to be done. + // Otherwise returns a pointer to a heap-allocated object that + // describes the compaction. Caller should delete the result. + Compaction* PickCompaction(); + + // Return a compaction object for compacting the range [begin,end] in + // the specified level. Returns NULL if there is nothing in that + // level that overlaps the specified range. Caller should delete + // the result. + Compaction* CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t MaxNextLevelOverlappingBytes(); + + // Create an iterator that reads over the compaction inputs for "*c". + // The caller should delete the iterator when no longer needed. + Iterator* MakeInputIterator(Compaction* c); + + // Returns true iff some level needs a compaction. + bool NeedsCompaction() const { + Version* v = current_; + return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL); + } + + // Add all files listed in any live version to *live. + // May also mutate some internal state. + void AddLiveFiles(std::set* live); + + // Return the approximate offset in the database of the data for + // "key" as of version "v". + uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); + + // Return a human-readable short (single-line) summary of the number + // of files per level. Uses *scratch as backing store. + struct LevelSummaryStorage { + char buffer[100]; + }; + const char* LevelSummary(LevelSummaryStorage* scratch) const; + + private: + class Builder; + + friend class Compaction; + friend class Version; + + void Finalize(Version* v); + + void GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest); + + void GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest); + + void SetupOtherInputs(Compaction* c); + + // Save current contents to *log + Status WriteSnapshot(log::Writer* log); + + void AppendVersion(Version* v); + + bool ManifestContains(const std::string& record) const; + + Env* const env_; + const std::string dbname_; + const Options* const options_; + TableCache* const table_cache_; + const InternalKeyComparator icmp_; + uint64_t next_file_number_; + uint64_t manifest_file_number_; + uint64_t last_sequence_; + uint64_t log_number_; + uint64_t prev_log_number_; // 0 or backing store for memtable being compacted + + // Opened lazily + WritableFile* descriptor_file_; + log::Writer* descriptor_log_; + Version dummy_versions_; // Head of circular doubly-linked list of versions. + Version* current_; // == dummy_versions_.prev_ + + // Per-level key at which the next compaction at that level should start. + // Either an empty string, or a valid InternalKey. + std::string compact_pointer_[config::kNumLevels]; + + // No copying allowed + VersionSet(const VersionSet&); + void operator=(const VersionSet&); +}; + +// A Compaction encapsulates information about a compaction. +class Compaction { + public: + ~Compaction(); + + // Return the level that is being compacted. Inputs from "level" + // and "level+1" will be merged to produce a set of "level+1" files. + int level() const { return level_; } + + // Return the object that holds the edits to the descriptor done + // by this compaction. + VersionEdit* edit() { return &edit_; } + + // "which" must be either 0 or 1 + int num_input_files(int which) const { return inputs_[which].size(); } + + // Return the ith input file at "level()+which" ("which" must be 0 or 1). + FileMetaData* input(int which, int i) const { return inputs_[which][i]; } + + // Maximum size of files to build during this compaction. + uint64_t MaxOutputFileSize() const { return max_output_file_size_; } + + // Is this a trivial compaction that can be implemented by just + // moving a single input file to the next level (no merging or splitting) + bool IsTrivialMove() const; + + // Add all inputs to this compaction as delete operations to *edit. + void AddInputDeletions(VersionEdit* edit); + + // Returns true if the information we have available guarantees that + // the compaction is producing data in "level+1" for which no data exists + // in levels greater than "level+1". + bool IsBaseLevelForKey(const Slice& user_key); + + // Returns true iff we should stop building the current output + // before processing "internal_key". + bool ShouldStopBefore(const Slice& internal_key); + + // Release the input version for the compaction, once the compaction + // is successful. + void ReleaseInputs(); + + private: + friend class Version; + friend class VersionSet; + + explicit Compaction(int level); + + int level_; + uint64_t max_output_file_size_; + Version* input_version_; + VersionEdit edit_; + + // Each compaction reads inputs from "level_" and "level_+1" + std::vector inputs_[2]; // The two sets of inputs + + // State used to check for number of of overlapping grandparent files + // (parent == level_ + 1, grandparent == level_ + 2) + std::vector grandparents_; + size_t grandparent_index_; // Index in grandparent_starts_ + bool seen_key_; // Some output key has been seen + int64_t overlapped_bytes_; // Bytes of overlap between current output + // and grandparent files + + // State for implementing IsBaseLevelForKey + + // level_ptrs_ holds indices into input_version_->levels_: our state + // is that we are positioned at one of the file ranges for each + // higher level than the ones involved in this compaction (i.e. for + // all L >= level_ + 2). + size_t level_ptrs_[config::kNumLevels]; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/src/leveldb/db/version_set_test.cc b/src/leveldb/db/version_set_test.cc new file mode 100644 index 0000000..501e34d --- /dev/null +++ b/src/leveldb/db/version_set_test.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class FindFileTest { + public: + std::vector files_; + bool disjoint_sorted_files_; + + FindFileTest() : disjoint_sorted_files_(true) { } + + ~FindFileTest() { + for (int i = 0; i < files_.size(); i++) { + delete files_[i]; + } + } + + void Add(const char* smallest, const char* largest, + SequenceNumber smallest_seq = 100, + SequenceNumber largest_seq = 100) { + FileMetaData* f = new FileMetaData; + f->number = files_.size() + 1; + f->smallest = InternalKey(smallest, smallest_seq, kTypeValue); + f->largest = InternalKey(largest, largest_seq, kTypeValue); + files_.push_back(f); + } + + int Find(const char* key) { + InternalKey target(key, 100, kTypeValue); + InternalKeyComparator cmp(BytewiseComparator()); + return FindFile(cmp, files_, target.Encode()); + } + + bool Overlaps(const char* smallest, const char* largest) { + InternalKeyComparator cmp(BytewiseComparator()); + Slice s(smallest != NULL ? smallest : ""); + Slice l(largest != NULL ? largest : ""); + return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_, + (smallest != NULL ? &s : NULL), + (largest != NULL ? &l : NULL)); + } +}; + +TEST(FindFileTest, Empty) { + ASSERT_EQ(0, Find("foo")); + ASSERT_TRUE(! Overlaps("a", "z")); + ASSERT_TRUE(! Overlaps(NULL, "z")); + ASSERT_TRUE(! Overlaps("a", NULL)); + ASSERT_TRUE(! Overlaps(NULL, NULL)); +} + +TEST(FindFileTest, Single) { + Add("p", "q"); + ASSERT_EQ(0, Find("a")); + ASSERT_EQ(0, Find("p")); + ASSERT_EQ(0, Find("p1")); + ASSERT_EQ(0, Find("q")); + ASSERT_EQ(1, Find("q1")); + ASSERT_EQ(1, Find("z")); + + ASSERT_TRUE(! Overlaps("a", "b")); + ASSERT_TRUE(! Overlaps("z1", "z2")); + ASSERT_TRUE(Overlaps("a", "p")); + ASSERT_TRUE(Overlaps("a", "q")); + ASSERT_TRUE(Overlaps("a", "z")); + ASSERT_TRUE(Overlaps("p", "p1")); + ASSERT_TRUE(Overlaps("p", "q")); + ASSERT_TRUE(Overlaps("p", "z")); + ASSERT_TRUE(Overlaps("p1", "p2")); + ASSERT_TRUE(Overlaps("p1", "z")); + ASSERT_TRUE(Overlaps("q", "q")); + ASSERT_TRUE(Overlaps("q", "q1")); + + ASSERT_TRUE(! Overlaps(NULL, "j")); + ASSERT_TRUE(! Overlaps("r", NULL)); + ASSERT_TRUE(Overlaps(NULL, "p")); + ASSERT_TRUE(Overlaps(NULL, "p1")); + ASSERT_TRUE(Overlaps("q", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); +} + + +TEST(FindFileTest, Multiple) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_EQ(0, Find("100")); + ASSERT_EQ(0, Find("150")); + ASSERT_EQ(0, Find("151")); + ASSERT_EQ(0, Find("199")); + ASSERT_EQ(0, Find("200")); + ASSERT_EQ(1, Find("201")); + ASSERT_EQ(1, Find("249")); + ASSERT_EQ(1, Find("250")); + ASSERT_EQ(2, Find("251")); + ASSERT_EQ(2, Find("299")); + ASSERT_EQ(2, Find("300")); + ASSERT_EQ(2, Find("349")); + ASSERT_EQ(2, Find("350")); + ASSERT_EQ(3, Find("351")); + ASSERT_EQ(3, Find("400")); + ASSERT_EQ(3, Find("450")); + ASSERT_EQ(4, Find("451")); + + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("251", "299")); + ASSERT_TRUE(! Overlaps("451", "500")); + ASSERT_TRUE(! Overlaps("351", "399")); + + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); +} + +TEST(FindFileTest, MultipleNullBoundaries) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_TRUE(! Overlaps(NULL, "149")); + ASSERT_TRUE(! Overlaps("451", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); + ASSERT_TRUE(Overlaps(NULL, "150")); + ASSERT_TRUE(Overlaps(NULL, "199")); + ASSERT_TRUE(Overlaps(NULL, "200")); + ASSERT_TRUE(Overlaps(NULL, "201")); + ASSERT_TRUE(Overlaps(NULL, "400")); + ASSERT_TRUE(Overlaps(NULL, "800")); + ASSERT_TRUE(Overlaps("100", NULL)); + ASSERT_TRUE(Overlaps("200", NULL)); + ASSERT_TRUE(Overlaps("449", NULL)); + ASSERT_TRUE(Overlaps("450", NULL)); +} + +TEST(FindFileTest, OverlapSequenceChecks) { + Add("200", "200", 5000, 3000); + ASSERT_TRUE(! Overlaps("199", "199")); + ASSERT_TRUE(! Overlaps("201", "300")); + ASSERT_TRUE(Overlaps("200", "200")); + ASSERT_TRUE(Overlaps("190", "200")); + ASSERT_TRUE(Overlaps("200", "210")); +} + +TEST(FindFileTest, OverlappingFiles) { + Add("150", "600"); + Add("400", "500"); + disjoint_sorted_files_ = false; + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("601", "700")); + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); + ASSERT_TRUE(Overlaps("450", "700")); + ASSERT_TRUE(Overlaps("600", "700")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/write_batch.cc b/src/leveldb/db/write_batch.cc new file mode 100644 index 0000000..33f4a42 --- /dev/null +++ b/src/leveldb/db/write_batch.cc @@ -0,0 +1,147 @@ +// 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. +// +// WriteBatch::rep_ := +// sequence: fixed64 +// count: fixed32 +// data: record[count] +// record := +// kTypeValue varstring varstring | +// kTypeDeletion varstring +// varstring := +// len: varint32 +// data: uint8[len] + +#include "leveldb/write_batch.h" + +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "util/coding.h" + +namespace leveldb { + +// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. +static const size_t kHeader = 12; + +WriteBatch::WriteBatch() { + Clear(); +} + +WriteBatch::~WriteBatch() { } + +WriteBatch::Handler::~Handler() { } + +void WriteBatch::Clear() { + rep_.clear(); + rep_.resize(kHeader); +} + +Status WriteBatch::Iterate(Handler* handler) const { + Slice input(rep_); + if (input.size() < kHeader) { + return Status::Corruption("malformed WriteBatch (too small)"); + } + + input.remove_prefix(kHeader); + Slice key, value; + int found = 0; + while (!input.empty()) { + found++; + char tag = input[0]; + input.remove_prefix(1); + switch (tag) { + case kTypeValue: + if (GetLengthPrefixedSlice(&input, &key) && + GetLengthPrefixedSlice(&input, &value)) { + handler->Put(key, value); + } else { + return Status::Corruption("bad WriteBatch Put"); + } + break; + case kTypeDeletion: + if (GetLengthPrefixedSlice(&input, &key)) { + handler->Delete(key); + } else { + return Status::Corruption("bad WriteBatch Delete"); + } + break; + default: + return Status::Corruption("unknown WriteBatch tag"); + } + } + if (found != WriteBatchInternal::Count(this)) { + return Status::Corruption("WriteBatch has wrong count"); + } else { + return Status::OK(); + } +} + +int WriteBatchInternal::Count(const WriteBatch* b) { + return DecodeFixed32(b->rep_.data() + 8); +} + +void WriteBatchInternal::SetCount(WriteBatch* b, int n) { + EncodeFixed32(&b->rep_[8], n); +} + +SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { + return SequenceNumber(DecodeFixed64(b->rep_.data())); +} + +void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { + EncodeFixed64(&b->rep_[0], seq); +} + +void WriteBatch::Put(const Slice& key, const Slice& value) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeValue)); + PutLengthPrefixedSlice(&rep_, key); + PutLengthPrefixedSlice(&rep_, value); +} + +void WriteBatch::Delete(const Slice& key) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeDeletion)); + PutLengthPrefixedSlice(&rep_, key); +} + +namespace { +class MemTableInserter : public WriteBatch::Handler { + public: + SequenceNumber sequence_; + MemTable* mem_; + + virtual void Put(const Slice& key, const Slice& value) { + mem_->Add(sequence_, kTypeValue, key, value); + sequence_++; + } + virtual void Delete(const Slice& key) { + mem_->Add(sequence_, kTypeDeletion, key, Slice()); + sequence_++; + } +}; +} // namespace + +Status WriteBatchInternal::InsertInto(const WriteBatch* b, + MemTable* memtable) { + MemTableInserter inserter; + inserter.sequence_ = WriteBatchInternal::Sequence(b); + inserter.mem_ = memtable; + return b->Iterate(&inserter); +} + +void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { + assert(contents.size() >= kHeader); + b->rep_.assign(contents.data(), contents.size()); +} + +void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { + SetCount(dst, Count(dst) + Count(src)); + assert(src->rep_.size() >= kHeader); + dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); +} + +} // namespace leveldb diff --git a/src/leveldb/db/write_batch_internal.h b/src/leveldb/db/write_batch_internal.h new file mode 100644 index 0000000..4423a7f --- /dev/null +++ b/src/leveldb/db/write_batch_internal.h @@ -0,0 +1,49 @@ +// 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_WRITE_BATCH_INTERNAL_H_ +#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ + +#include "leveldb/write_batch.h" + +namespace leveldb { + +class MemTable; + +// WriteBatchInternal provides static methods for manipulating a +// WriteBatch that we don't want in the public WriteBatch interface. +class WriteBatchInternal { + public: + // Return the number of entries in the batch. + static int Count(const WriteBatch* batch); + + // Set the count for the number of entries in the batch. + static void SetCount(WriteBatch* batch, int n); + + // Return the seqeunce number for the start of this batch. + static SequenceNumber Sequence(const WriteBatch* batch); + + // Store the specified number as the seqeunce number for the start of + // this batch. + static void SetSequence(WriteBatch* batch, SequenceNumber seq); + + static Slice Contents(const WriteBatch* batch) { + return Slice(batch->rep_); + } + + static size_t ByteSize(const WriteBatch* batch) { + return batch->rep_.size(); + } + + static void SetContents(WriteBatch* batch, const Slice& contents); + + static Status InsertInto(const WriteBatch* batch, MemTable* memtable); + + static void Append(WriteBatch* dst, const WriteBatch* src); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/src/leveldb/db/write_batch_test.cc b/src/leveldb/db/write_batch_test.cc new file mode 100644 index 0000000..9064e3d --- /dev/null +++ b/src/leveldb/db/write_batch_test.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string PrintContents(WriteBatch* b) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* mem = new MemTable(cmp); + mem->Ref(); + std::string state; + Status s = WriteBatchInternal::InsertInto(b, mem); + int count = 0; + Iterator* iter = mem->NewIterator(); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey ikey; + ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey)); + switch (ikey.type) { + case kTypeValue: + state.append("Put("); + state.append(ikey.user_key.ToString()); + state.append(", "); + state.append(iter->value().ToString()); + state.append(")"); + count++; + break; + case kTypeDeletion: + state.append("Delete("); + state.append(ikey.user_key.ToString()); + state.append(")"); + count++; + break; + } + state.append("@"); + state.append(NumberToString(ikey.sequence)); + } + delete iter; + if (!s.ok()) { + state.append("ParseError()"); + } else if (count != WriteBatchInternal::Count(b)) { + state.append("CountMismatch()"); + } + mem->Unref(); + return state; +} + +class WriteBatchTest { }; + +TEST(WriteBatchTest, Empty) { + WriteBatch batch; + ASSERT_EQ("", PrintContents(&batch)); + ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); +} + +TEST(WriteBatchTest, Multiple) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + batch.Put(Slice("baz"), Slice("boo")); + WriteBatchInternal::SetSequence(&batch, 100); + ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch)); + ASSERT_EQ(3, WriteBatchInternal::Count(&batch)); + ASSERT_EQ("Put(baz, boo)@102" + "Delete(box)@101" + "Put(foo, bar)@100", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Corruption) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + WriteBatchInternal::SetSequence(&batch, 200); + Slice contents = WriteBatchInternal::Contents(&batch); + WriteBatchInternal::SetContents(&batch, + Slice(contents.data(),contents.size()-1)); + ASSERT_EQ("Put(foo, bar)@200" + "ParseError()", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Append) { + WriteBatch b1, b2; + WriteBatchInternal::SetSequence(&b1, 200); + WriteBatchInternal::SetSequence(&b2, 300); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("", + PrintContents(&b1)); + b2.Put("a", "va"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200", + PrintContents(&b1)); + b2.Clear(); + b2.Put("b", "vb"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@201", + PrintContents(&b1)); + b2.Delete("foo"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@202" + "Put(b, vb)@201" + "Delete(foo)@203", + PrintContents(&b1)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/doc/bench/db_bench_sqlite3.cc b/src/leveldb/doc/bench/db_bench_sqlite3.cc new file mode 100644 index 0000000..e63aaa8 --- /dev/null +++ b/src/leveldb/doc/bench/db_bench_sqlite3.cc @@ -0,0 +1,718 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "util/histogram.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// +// fillseq -- write N values in sequential key order in async mode +// fillseqsync -- write N/100 values in sequential key order in sync mode +// fillseqbatch -- batch write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// fillrandsync -- write N/100 values in random key order in sync mode +// fillrandbatch -- batch write N values in sequential key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillrand100K -- write N/1000 100K values in random order in async mode +// fillseq100K -- write N/1000 100K values in sequential order in async mode +// readseq -- read N times sequentially +// readrandom -- read N times in random order +// readrand100K -- read N/1000 100K values in sequential order in async mode +static const char* FLAGS_benchmarks = + "fillseq," + "fillseqsync," + "fillseqbatch," + "fillrandom," + "fillrandsync," + "fillrandbatch," + "overwrite," + "overwritebatch," + "readrandom," + "readseq," + "fillrand100K," + "fillseq100K," + "readseq," + "readrand100K," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Page size. Default 1 KB. +static int FLAGS_page_size = 1024; + +// Number of pages. +// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB. +static int FLAGS_num_pages = 4096; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// If true, we allow batch writes to occur +static bool FLAGS_transaction = true; + +// If true, we enable Write-Ahead Logging +static bool FLAGS_WAL_enabled = true; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +inline +static void ExecErrorCheck(int status, char *err_msg) { + if (status != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", err_msg); + sqlite3_free(err_msg); + exit(1); + } +} + +inline +static void StepErrorCheck(int status) { + if (status != SQLITE_DONE) { + fprintf(stderr, "SQL step error: status = %d\n", status); + exit(1); + } +} + +inline +static void ErrorCheck(int status) { + if (status != SQLITE_OK) { + fprintf(stderr, "sqlite3 error: status = %d\n", status); + exit(1); + } +} + +inline +static void WalCheckpoint(sqlite3* db_) { + // Flush all writes to disk + if (FLAGS_WAL_enabled) { + sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL); + } +} + +namespace leveldb { + +// Helper for quickly generating random data. +namespace { +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +} // namespace + +class Benchmark { + private: + sqlite3* db_; + int db_num_; + int num_; + int reads_; + double start_; + double last_op_finish_; + int64_t bytes_; + std::string message_; + Histogram hist_; + RandomGenerator gen_; + Random rand_; + + // State kept for progress messages + int done_; + int next_report_; // When to report next + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + } + + void PrintEnvironment() { + fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + void Start() { + start_ = Env::Default()->NowMicros() * 1e-6; + bytes_ = 0; + message_.clear(); + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + next_report_ = 100; + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros() * 1e-6; + double micros = (now - last_op_finish_) * 1e6; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void Stop(const Slice& name) { + double finish = Env::Default()->NowMicros() * 1e-6; + + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + if (bytes_ > 0) { + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / (finish - start_)); + if (!message_.empty()) { + message_ = std::string(rate) + " " + message_; + } else { + message_ = rate; + } + } + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + (finish - start_) * 1e6 / done_, + (message_.empty() ? "" : " "), + message_.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } + + public: + enum Order { + SEQUENTIAL, + RANDOM + }; + enum DBState { + FRESH, + EXISTING + }; + + Benchmark() + : db_(NULL), + db_num_(0), + num_(FLAGS_num), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + bytes_(0), + rand_(301) { + std::vector files; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + Env::Default()->GetChildren(test_dir, &files); + if (!FLAGS_use_existing_db) { + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("dbbench_sqlite3")) { + std::string file_name(test_dir); + file_name += "/"; + file_name += files[i]; + Env::Default()->DeleteFile(file_name.c_str()); + } + } + } + } + + ~Benchmark() { + int status = sqlite3_close(db_); + ErrorCheck(status); + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + bytes_ = 0; + Start(); + + bool known = true; + bool write_sync = false; + if (name == Slice("fillseq")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseqbatch")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("fillrandom")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillrandbatch")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("overwrite")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("overwritebatch")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("fillrandsync")) { + write_sync = true; + Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseqsync")) { + write_sync = true; + Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillrand100K")) { + Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseq100K")) { + Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); + WalCheckpoint(db_); + } else if (name == Slice("readseq")) { + ReadSequential(); + } else if (name == Slice("readrandom")) { + Read(RANDOM, 1); + } else if (name == Slice("readrand100K")) { + int n = reads_; + reads_ /= 1000; + Read(RANDOM, 1); + reads_ = n; + } else { + known = false; + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + if (known) { + Stop(name); + } + } + } + + void Open() { + assert(db_ == NULL); + + int status; + char file_name[100]; + char* err_msg = NULL; + db_num_++; + + // Open database + std::string tmp_dir; + Env::Default()->GetTestDirectory(&tmp_dir); + snprintf(file_name, sizeof(file_name), + "%s/dbbench_sqlite3-%d.db", + tmp_dir.c_str(), + db_num_); + status = sqlite3_open(file_name, &db_); + if (status) { + fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_)); + exit(1); + } + + // Change SQLite cache size + char cache_size[100]; + snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d", + FLAGS_num_pages); + status = sqlite3_exec(db_, cache_size, NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + + // FLAGS_page_size is defaulted to 1024 + if (FLAGS_page_size != 1024) { + char page_size[100]; + snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d", + FLAGS_page_size); + status = sqlite3_exec(db_, page_size, NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + + // Change journal mode to WAL if WAL enabled flag is on + if (FLAGS_WAL_enabled) { + std::string WAL_stmt = "PRAGMA journal_mode = WAL"; + + // LevelDB's default cache size is a combined 4 MB + std::string WAL_checkpoint = "PRAGMA wal_autocheckpoint = 4096"; + status = sqlite3_exec(db_, WAL_stmt.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + status = sqlite3_exec(db_, WAL_checkpoint.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + + // Change locking mode to exclusive and create tables/index for database + std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE"; + std::string create_stmt = + "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))"; + std::string stmt_array[] = { locking_stmt, create_stmt }; + int stmt_array_length = sizeof(stmt_array) / sizeof(std::string); + for (int i = 0; i < stmt_array_length; i++) { + status = sqlite3_exec(db_, stmt_array[i].c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + } + + void Write(bool write_sync, Order order, DBState state, + int num_entries, int value_size, int entries_per_batch) { + // Create new database if state == FRESH + if (state == FRESH) { + if (FLAGS_use_existing_db) { + message_ = "skipping (--use_existing_db is true)"; + return; + } + sqlite3_close(db_); + db_ = NULL; + Open(); + Start(); + } + + if (num_entries != num_) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_entries); + message_ = msg; + } + + char* err_msg = NULL; + int status; + + sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt; + std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)"; + std::string begin_trans_str = "BEGIN TRANSACTION;"; + std::string end_trans_str = "END TRANSACTION;"; + + // Check for synchronous flag in options + std::string sync_stmt = (write_sync) ? "PRAGMA synchronous = FULL" : + "PRAGMA synchronous = OFF"; + status = sqlite3_exec(db_, sync_stmt.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + + // Preparing sqlite3 statements + status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, + &replace_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, + &begin_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, + &end_trans_stmt, NULL); + ErrorCheck(status); + + bool transaction = (entries_per_batch > 1); + for (int i = 0; i < num_entries; i += entries_per_batch) { + // Begin write transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(begin_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(begin_trans_stmt); + ErrorCheck(status); + } + + // Create and execute SQL statements + for (int j = 0; j < entries_per_batch; j++) { + const char* value = gen_.Generate(value_size).data(); + + // Create values for key-value pair + const int k = (order == SEQUENTIAL) ? i + j : + (rand_.Next() % num_entries); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + + // Bind KV values into replace_stmt + status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC); + ErrorCheck(status); + status = sqlite3_bind_blob(replace_stmt, 2, value, + value_size, SQLITE_STATIC); + ErrorCheck(status); + + // Execute replace_stmt + bytes_ += value_size + strlen(key); + status = sqlite3_step(replace_stmt); + StepErrorCheck(status); + + // Reset SQLite statement for another use + status = sqlite3_clear_bindings(replace_stmt); + ErrorCheck(status); + status = sqlite3_reset(replace_stmt); + ErrorCheck(status); + + FinishedSingleOp(); + } + + // End write transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(end_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(end_trans_stmt); + ErrorCheck(status); + } + } + + status = sqlite3_finalize(replace_stmt); + ErrorCheck(status); + status = sqlite3_finalize(begin_trans_stmt); + ErrorCheck(status); + status = sqlite3_finalize(end_trans_stmt); + ErrorCheck(status); + } + + void Read(Order order, int entries_per_batch) { + int status; + sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt; + + std::string read_str = "SELECT * FROM test WHERE key = ?"; + std::string begin_trans_str = "BEGIN TRANSACTION;"; + std::string end_trans_str = "END TRANSACTION;"; + + // Preparing sqlite3 statements + status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, + &begin_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, + &end_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, NULL); + ErrorCheck(status); + + bool transaction = (entries_per_batch > 1); + for (int i = 0; i < reads_; i += entries_per_batch) { + // Begin read transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(begin_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(begin_trans_stmt); + ErrorCheck(status); + } + + // Create and execute SQL statements + for (int j = 0; j < entries_per_batch; j++) { + // Create key value + char key[100]; + int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_); + snprintf(key, sizeof(key), "%016d", k); + + // Bind key value into read_stmt + status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC); + ErrorCheck(status); + + // Execute read statement + while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {} + StepErrorCheck(status); + + // Reset SQLite statement for another use + status = sqlite3_clear_bindings(read_stmt); + ErrorCheck(status); + status = sqlite3_reset(read_stmt); + ErrorCheck(status); + FinishedSingleOp(); + } + + // End read transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(end_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(end_trans_stmt); + ErrorCheck(status); + } + } + + status = sqlite3_finalize(read_stmt); + ErrorCheck(status); + status = sqlite3_finalize(begin_trans_stmt); + ErrorCheck(status); + status = sqlite3_finalize(end_trans_stmt); + ErrorCheck(status); + } + + void ReadSequential() { + int status; + sqlite3_stmt *pStmt; + std::string read_str = "SELECT * FROM test ORDER BY key"; + + status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, NULL); + ErrorCheck(status); + for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) { + bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2); + FinishedSingleOp(); + } + + status = sqlite3_finalize(pStmt); + ErrorCheck(status); + } + +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + std::string default_db_path; + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } 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], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) { + FLAGS_transaction = false; + } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { + FLAGS_page_size = n; + } else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) { + FLAGS_num_pages = n; + } else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_WAL_enabled = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/src/leveldb/doc/bench/db_bench_tree_db.cc b/src/leveldb/doc/bench/db_bench_tree_db.cc new file mode 100644 index 0000000..ed86f03 --- /dev/null +++ b/src/leveldb/doc/bench/db_bench_tree_db.cc @@ -0,0 +1,528 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "util/histogram.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillseqsync -- write N/100 values in sequential key order in sync mode +// fillrandsync -- write N/100 values in random key order in sync mode +// fillrand100K -- write N/1000 100K values in random order in async mode +// fillseq100K -- write N/1000 100K values in seq order in async mode +// readseq -- read N times sequentially +// readseq100K -- read N/1000 100K values in sequential order in async mode +// readrand100K -- read N/1000 100K values in sequential order in async mode +// readrandom -- read N times in random order +static const char* FLAGS_benchmarks = + "fillseq," + "fillseqsync," + "fillrandsync," + "fillrandom," + "overwrite," + "readrandom," + "readseq," + "fillrand100K," + "fillseq100K," + "readseq100K," + "readrand100K," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Cache size. Default 4 MB +static int FLAGS_cache_size = 4194304; + +// Page size. Default 1 KB +static int FLAGS_page_size = 1024; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// Compression flag. If true, compression is on. If false, compression +// is off. +static bool FLAGS_compression = true; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +inline +static void DBSynchronize(kyotocabinet::TreeDB* db_) +{ + // Synchronize will flush writes to disk + if (!db_->synchronize()) { + fprintf(stderr, "synchronize error: %s\n", db_->error().name()); + } +} + +namespace leveldb { + +// Helper for quickly generating random data. +namespace { +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +} // namespace + +class Benchmark { + private: + kyotocabinet::TreeDB* db_; + int db_num_; + int num_; + int reads_; + double start_; + double last_op_finish_; + int64_t bytes_; + std::string message_; + Histogram hist_; + RandomGenerator gen_; + Random rand_; + kyotocabinet::LZOCompressor comp_; + + // State kept for progress messages + int done_; + int next_report_; // When to report next + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + } + + void PrintEnvironment() { + fprintf(stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n", + kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + void Start() { + start_ = Env::Default()->NowMicros() * 1e-6; + bytes_ = 0; + message_.clear(); + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + next_report_ = 100; + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros() * 1e-6; + double micros = (now - last_op_finish_) * 1e6; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void Stop(const Slice& name) { + double finish = Env::Default()->NowMicros() * 1e-6; + + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + if (bytes_ > 0) { + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / (finish - start_)); + if (!message_.empty()) { + message_ = std::string(rate) + " " + message_; + } else { + message_ = rate; + } + } + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + (finish - start_) * 1e6 / done_, + (message_.empty() ? "" : " "), + message_.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } + + public: + enum Order { + SEQUENTIAL, + RANDOM + }; + enum DBState { + FRESH, + EXISTING + }; + + Benchmark() + : db_(NULL), + num_(FLAGS_num), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + bytes_(0), + rand_(301) { + std::vector files; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + Env::Default()->GetChildren(test_dir.c_str(), &files); + if (!FLAGS_use_existing_db) { + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("dbbench_polyDB")) { + std::string file_name(test_dir); + file_name += "/"; + file_name += files[i]; + Env::Default()->DeleteFile(file_name.c_str()); + } + } + } + } + + ~Benchmark() { + if (!db_->close()) { + fprintf(stderr, "close error: %s\n", db_->error().name()); + } + } + + void Run() { + PrintHeader(); + Open(false); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + Start(); + + bool known = true; + bool write_sync = false; + if (name == Slice("fillseq")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); + + } else if (name == Slice("fillrandom")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("overwrite")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrandsync")) { + write_sync = true; + Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillseqsync")) { + write_sync = true; + Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrand100K")) { + Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); + DBSynchronize(db_); + } else if (name == Slice("fillseq100K")) { + Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); + DBSynchronize(db_); + } else if (name == Slice("readseq")) { + ReadSequential(); + } else if (name == Slice("readrandom")) { + ReadRandom(); + } else if (name == Slice("readrand100K")) { + int n = reads_; + reads_ /= 1000; + ReadRandom(); + reads_ = n; + } else if (name == Slice("readseq100K")) { + int n = reads_; + reads_ /= 1000; + ReadSequential(); + reads_ = n; + } else { + known = false; + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + if (known) { + Stop(name); + } + } + } + + private: + void Open(bool sync) { + assert(db_ == NULL); + + // Initialize db_ + db_ = new kyotocabinet::TreeDB(); + char file_name[100]; + db_num_++; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + snprintf(file_name, sizeof(file_name), + "%s/dbbench_polyDB-%d.kct", + test_dir.c_str(), + db_num_); + + // Create tuning options and open the database + int open_options = kyotocabinet::PolyDB::OWRITER | + kyotocabinet::PolyDB::OCREATE; + int tune_options = kyotocabinet::TreeDB::TSMALL | + kyotocabinet::TreeDB::TLINEAR; + if (FLAGS_compression) { + tune_options |= kyotocabinet::TreeDB::TCOMPRESS; + db_->tune_compressor(&comp_); + } + db_->tune_options(tune_options); + db_->tune_page_cache(FLAGS_cache_size); + db_->tune_page(FLAGS_page_size); + db_->tune_map(256LL<<20); + if (sync) { + open_options |= kyotocabinet::PolyDB::OAUTOSYNC; + } + if (!db_->open(file_name, open_options)) { + fprintf(stderr, "open error: %s\n", db_->error().name()); + } + } + + void Write(bool sync, Order order, DBState state, + int num_entries, int value_size, int entries_per_batch) { + // Create new database if state == FRESH + if (state == FRESH) { + if (FLAGS_use_existing_db) { + message_ = "skipping (--use_existing_db is true)"; + return; + } + delete db_; + db_ = NULL; + Open(sync); + Start(); // Do not count time taken to destroy/open + } + + if (num_entries != num_) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_entries); + message_ = msg; + } + + // Write to database + for (int i = 0; i < num_entries; i++) + { + const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + bytes_ += value_size + strlen(key); + std::string cpp_key = key; + if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) { + fprintf(stderr, "set error: %s\n", db_->error().name()); + } + FinishedSingleOp(); + } + } + + void ReadSequential() { + kyotocabinet::DB::Cursor* cur = db_->cursor(); + cur->jump(); + std::string ckey, cvalue; + while (cur->get(&ckey, &cvalue, true)) { + bytes_ += ckey.size() + cvalue.size(); + FinishedSingleOp(); + } + delete cur; + } + + void ReadRandom() { + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = rand_.Next() % reads_; + snprintf(key, sizeof(key), "%016d", k); + db_->get(key, &value); + FinishedSingleOp(); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + std::string default_db_path; + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = 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) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { + FLAGS_page_size = n; + } else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_compression = (n == 1) ? true : false; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/src/leveldb/doc/benchmark.html b/src/leveldb/doc/benchmark.html new file mode 100644 index 0000000..c463977 --- /dev/null +++ b/src/leveldb/doc/benchmark.html @@ -0,0 +1,459 @@ + + + +LevelDB Benchmarks + + + + +

LevelDB Benchmarks

+

Google, July 2011

+
+ +

In order to test LevelDB's performance, we benchmark it against other well-established database implementations. We compare LevelDB (revision 39) against SQLite3 (version 3.7.6.3) and Kyoto Cabinet's (version 1.2.67) TreeDB (a B+Tree based key-value store). We would like to acknowledge Scott Hess and Mikio Hirabayashi for their suggestions and contributions to the SQLite3 and Kyoto Cabinet benchmarks, respectively.

+ +

Benchmarks were all performed on a six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz. (Note that LevelDB uses at most two CPUs since the benchmarks are single threaded: one to run the benchmark, and one for background compactions.) We ran the benchmarks on two machines (with identical processors), one with an Ext3 file system and one with an Ext4 file system. The machine with the Ext3 file system has a SATA Hitachi HDS721050CLA362 hard drive. The machine with the Ext4 file system has a SATA Samsung HD502HJ hard drive. Both hard drives spin at 7200 RPM and have hard drive write-caching enabled (using `hdparm -W 1 [device]`). The numbers reported below are the median of three measurements.

+ +

Benchmark Source Code

+

We wrote benchmark tools for SQLite and Kyoto TreeDB based on LevelDB's db_bench. The code for each of the benchmarks resides here:

+ + +

Custom Build Specifications

+
    +
  • LevelDB: LevelDB was compiled with the tcmalloc library and the Snappy compression library (revision 33). Assertions were disabled.
  • +
  • TreeDB: TreeDB was compiled using the LZO compression library (version 2.03). Furthermore, we enabled the TSMALL and TLINEAR options when opening the database in order to reduce the footprint of each record.
  • +
  • SQLite: We tuned SQLite's performance, by setting its locking mode to exclusive. We also enabled SQLite's write-ahead logging.
  • +
+ +

1. Baseline Performance

+

This section gives the baseline performance of all the +databases. Following sections show how performance changes as various +parameters are varied. For the baseline:

+
    +
  • Each database is allowed 4 MB of cache memory.
  • +
  • Databases are opened in asynchronous write mode. + (LevelDB's sync option, TreeDB's OAUTOSYNC option, and + SQLite3's synchronous options are all turned off). I.e., + every write is pushed to the operating system, but the + benchmark does not wait for the write to reach the disk.
  • +
  • Keys are 16 bytes each.
  • +
  • Value are 100 bytes each (with enough redundancy so that + a simple compressor shrinks them to 50% of their original + size).
  • +
  • Sequential reads/writes traverse the key space in increasing order.
  • +
  • Random reads/writes traverse the key space in random order.
  • +
+ +

A. Sequential Reads

+ + + + + + + + + + +
LevelDB4,030,000 ops/sec
 
Kyoto TreeDB1,010,000 ops/sec
 
SQLite3383,000 ops/sec
 
+

B. Random Reads

+ + + + + + + + + + +
LevelDB129,000 ops/sec
 
Kyoto TreeDB151,000 ops/sec
 
SQLite3134,000 ops/sec
 
+

C. Sequential Writes

+ + + + + + + + + + +
LevelDB779,000 ops/sec
 
Kyoto TreeDB342,000 ops/sec
 
SQLite348,600 ops/sec
 
+

D. Random Writes

+ + + + + + + + + + +
LevelDB164,000 ops/sec
 
Kyoto TreeDB88,500 ops/sec
 
SQLite39,860 ops/sec
 
+ +

LevelDB outperforms both SQLite3 and TreeDB in sequential and random write operations and sequential read operations. Kyoto Cabinet has the fastest random read operations.

+ +

2. Write Performance under Different Configurations

+

A. Large Values

+

For this benchmark, we start with an empty database, and write 100,000 byte values (~50% compressible). To keep the benchmark running time reasonable, we stop after writing 1000 values.

+

Sequential Writes

+ + + + + + + + + + +
LevelDB1,100 ops/sec
 
Kyoto TreeDB1,000 ops/sec
 
SQLite31,600 ops/sec
 
+

Random Writes

+ + + + + + + + + + +
LevelDB480 ops/sec
 
Kyoto TreeDB1,100 ops/sec
 
SQLite31,600 ops/sec
 
+

LevelDB doesn't perform as well with large values of 100,000 bytes each. This is because LevelDB writes keys and values at least twice: first time to the transaction log, and second time (during a compaction) to a sorted file. +With larger values, LevelDB's per-operation efficiency is swamped by the +cost of extra copies of large values.

+

B. Batch Writes

+

A batch write is a set of writes that are applied atomically to the underlying database. A single batch of N writes may be significantly faster than N individual writes. The following benchmark writes one thousand batches where each batch contains one thousand 100-byte values. TreeDB does not support batch writes and is omitted from this benchmark.

+

Sequential Writes

+ + + + + + + + + +
LevelDB840,000 entries/sec
 
(1.08x baseline)
SQLite3124,000 entries/sec
 
(2.55x baseline)
+

Random Writes

+ + + + + + + + + +
LevelDB221,000 entries/sec
 
(1.35x baseline)
SQLite322,000 entries/sec
 
(2.23x baseline)
+ +

Because of the way LevelDB persistent storage is organized, batches of +random writes are not much slower (only a factor of 4x) than batches +of sequential writes.

+ +

C. Synchronous Writes

+

In the following benchmark, we enable the synchronous writing modes +of all of the databases. Since this change significantly slows down the +benchmark, we stop after 10,000 writes. For synchronous write tests, we've +disabled hard drive write-caching (using `hdparm -W 0 [device]`).

+
    +
  • For LevelDB, we set WriteOptions.sync = true.
  • +
  • In TreeDB, we enabled TreeDB's OAUTOSYNC option.
  • +
  • For SQLite3, we set "PRAGMA synchronous = FULL".
  • +
+

Sequential Writes

+ + + + + + + + + + + + + +
LevelDB100 ops/sec
 
(0.003x baseline)
Kyoto TreeDB7 ops/sec
 
(0.0004x baseline)
SQLite388 ops/sec
 
(0.002x baseline)
+

Random Writes

+ + + + + + + + + + + + + +
LevelDB100 ops/sec
 
(0.015x baseline)
Kyoto TreeDB8 ops/sec
 
(0.001x baseline)
SQLite388 ops/sec
 
(0.009x baseline)
+ +

Also see the ext4 performance numbers below +since synchronous writes behave significantly differently +on ext3 and ext4.

+ +

D. Turning Compression Off

+ +

In the baseline measurements, LevelDB and TreeDB were using +light-weight compression +(Snappy for LevelDB, +and LZO for +TreeDB). SQLite3, by default does not use compression. The +experiments below show what happens when compression is disabled in +all of the databases (the SQLite3 numbers are just a copy of +its baseline measurements):

+ +

Sequential Writes

+ + + + + + + + + + + + + +
LevelDB594,000 ops/sec
 
(0.76x baseline)
Kyoto TreeDB485,000 ops/sec
 
(1.42x baseline)
SQLite348,600 ops/sec
 
(1.00x baseline)
+

Random Writes

+ + + + + + + + + + + + + +
LevelDB135,000 ops/sec
 
(0.82x baseline)
Kyoto TreeDB159,000 ops/sec
 
(1.80x baseline)
SQLite39,860 ops/sec
 
(1.00x baseline)
+ +

LevelDB's write performance is better with compression than without +since compression decreases the amount of data that has to be written +to disk. Therefore LevelDB users can leave compression enabled in +most scenarios without having worry about a tradeoff between space +usage and performance. TreeDB's performance on the other hand is +better without compression than with compression. Presumably this is +because TreeDB's compression library (LZO) is more expensive than +LevelDB's compression library (Snappy).

+ +

E. Using More Memory

+

We increased the overall cache size for each database to 128 MB. For LevelDB, we partitioned 128 MB into a 120 MB write buffer and 8 MB of cache (up from 2 MB of write buffer and 2 MB of cache). For SQLite3, we kept the page size at 1024 bytes, but increased the number of pages to 131,072 (up from 4096). For TreeDB, we also kept the page size at 1024 bytes, but increased the cache size to 128 MB (up from 4 MB).

+

Sequential Writes

+ + + + + + + + + + + + + +
LevelDB812,000 ops/sec
 
(1.04x baseline)
Kyoto TreeDB321,000 ops/sec
 
(0.94x baseline)
SQLite348,500 ops/sec
 
(1.00x baseline)
+

Random Writes

+ + + + + + + + + + + + + +
LevelDB355,000 ops/sec
 
(2.16x baseline)
Kyoto TreeDB284,000 ops/sec
 
(3.21x baseline)
SQLite39,670 ops/sec
 
(0.98x baseline)
+ +

SQLite's performance does not change substantially when compared to +the baseline, but the random write performance for both LevelDB and +TreeDB increases significantly. LevelDB's performance improves +because a larger write buffer reduces the need to merge sorted files +(since it creates a smaller number of larger sorted files). TreeDB's +performance goes up because the entire database is available in memory +for fast in-place updates.

+ +

3. Read Performance under Different Configurations

+

A. Larger Caches

+

We increased the overall memory usage to 128 MB for each database. +For LevelDB, we allocated 8 MB to LevelDB's write buffer and 120 MB +to LevelDB's cache. The other databases don't differentiate between a +write buffer and a cache, so we simply set their cache size to 128 +MB.

+

Sequential Reads

+ + + + + + + + + + + + + +
LevelDB5,210,000 ops/sec
 
(1.29x baseline)
Kyoto TreeDB1,070,000 ops/sec
 
(1.06x baseline)
SQLite3609,000 ops/sec
 
(1.59x baseline)
+ +

Random Reads

+ + + + + + + + + + + + + +
LevelDB190,000 ops/sec
 
(1.47x baseline)
Kyoto TreeDB463,000 ops/sec
 
(3.07x baseline)
SQLite3186,000 ops/sec
 
(1.39x baseline)
+ +

As expected, the read performance of all of the databases increases +when the caches are enlarged. In particular, TreeDB seems to make +very effective use of a cache that is large enough to hold the entire +database.

+ +

B. No Compression Reads

+

For this benchmark, we populated a database with 1 million entries consisting of 16 byte keys and 100 byte values. We compiled LevelDB and Kyoto Cabinet without compression support, so results that are read out from the database are already uncompressed. We've listed the SQLite3 baseline read performance as a point of comparison.

+

Sequential Reads

+ + + + + + + + + + + + + +
LevelDB4,880,000 ops/sec
 
(1.21x baseline)
Kyoto TreeDB1,230,000 ops/sec
 
(3.60x baseline)
SQLite3383,000 ops/sec
 
(1.00x baseline)
+

Random Reads

+ + + + + + + + + + + + + +
LevelDB149,000 ops/sec
 
(1.16x baseline)
Kyoto TreeDB175,000 ops/sec
 
(1.16x baseline)
SQLite3134,000 ops/sec
 
(1.00x baseline)
+ +

Performance of both LevelDB and TreeDB improves a small amount when +compression is disabled. Note however that under different workloads, +performance may very well be better with compression if it allows more +of the working set to fit in memory.

+ +

Note about Ext4 Filesystems

+

The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.

+ +

Acknowledgements

+

Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.

+ + diff --git a/src/leveldb/doc/doc.css b/src/leveldb/doc/doc.css new file mode 100644 index 0000000..700c564 --- /dev/null +++ b/src/leveldb/doc/doc.css @@ -0,0 +1,89 @@ +body { + margin-left: 0.5in; + margin-right: 0.5in; + background: white; + color: black; +} + +h1 { + margin-left: -0.2in; + font-size: 14pt; +} +h2 { + margin-left: -0in; + font-size: 12pt; +} +h3 { + margin-left: -0in; +} +h4 { + margin-left: -0in; +} +hr { + margin-left: -0in; +} + +/* Definition lists: definition term bold */ +dt { + font-weight: bold; +} + +address { + text-align: center; +} +code,samp,var { + color: blue; +} +kbd { + color: #600000; +} +div.note p { + float: right; + width: 3in; + margin-right: 0%; + padding: 1px; + border: 2px solid #6060a0; + background-color: #fffff0; +} + +ul { + margin-top: -0em; + margin-bottom: -0em; +} + +ol { + margin-top: -0em; + margin-bottom: -0em; +} + +UL.nobullets { + list-style-type: none; + list-style-image: none; + margin-left: -1em; +} + +p { + margin: 1em 0 1em 0; + padding: 0 0 0 0; +} + +pre { + line-height: 1.3em; + padding: 0.4em 0 0.8em 0; + margin: 0 0 0 0; + border: 0 0 0 0; + color: blue; +} + +.datatable { + margin-left: auto; + margin-right: auto; + margin-top: 2em; + margin-bottom: 2em; + border: 1px solid; +} + +.datatable td,th { + padding: 0 0.5em 0 0.5em; + text-align: right; +} diff --git a/src/leveldb/doc/impl.html b/src/leveldb/doc/impl.html new file mode 100644 index 0000000..e870795 --- /dev/null +++ b/src/leveldb/doc/impl.html @@ -0,0 +1,213 @@ + + + + +Leveldb file layout and compactions + + + + +

Files

+ +The implementation of leveldb is similar in spirit to the +representation of a single + +Bigtable tablet (section 5.3). +However the organization of the files that make up the representation +is somewhat different and is explained below. + +

+Each database is represented by a set of files stored in a directory. +There are several different types of files as documented below: +

+

Log files

+

+A log file (*.log) stores a sequence of recent updates. Each update +is appended to the current log file. When the log file reaches a +pre-determined size (approximately 4MB by default), it is converted +to a sorted table (see below) and a new log file is created for future +updates. +

+A copy of the current log file is kept in an in-memory structure (the +memtable). This copy is consulted on every read so that read +operations reflect all logged updates. +

+

Sorted tables

+

+A sorted table (*.sst) stores a sequence of entries sorted by key. +Each entry is either a value for the key, or a deletion marker for the +key. (Deletion markers are kept around to hide obsolete values +present in older sorted tables). +

+The set of sorted tables are organized into a sequence of levels. The +sorted table generated from a log file is placed in a special young +level (also called level-0). When the number of young files exceeds a +certain threshold (currently four), all of the young files are merged +together with all of the overlapping level-1 files to produce a +sequence of new level-1 files (we create a new level-1 file for every +2MB of data.) +

+Files in the young level may contain overlapping keys. However files +in other levels have distinct non-overlapping key ranges. Consider +level number L where L >= 1. When the combined size of files in +level-L exceeds (10^L) MB (i.e., 10MB for level-1, 100MB for level-2, +...), one file in level-L, and all of the overlapping files in +level-(L+1) are merged to form a set of new files for level-(L+1). +These merges have the effect of gradually migrating new updates from +the young level to the largest level using only bulk reads and writes +(i.e., minimizing expensive seeks). + +

Manifest

+

+A MANIFEST file lists the set of sorted tables that make up each +level, the corresponding key ranges, and other important metadata. +A new MANIFEST file (with a new number embedded in the file name) +is created whenever the database is reopened. The MANIFEST file is +formatted as a log, and changes made to the serving state (as files +are added or removed) are appended to this log. +

+

Current

+

+CURRENT is a simple text file that contains the name of the latest +MANIFEST file. +

+

Info logs

+

+Informational messages are printed to files named LOG and LOG.old. +

+

Others

+

+Other files used for miscellaneous purposes may also be present +(LOCK, *.dbtmp). + +

Level 0

+When the log file grows above a certain size (1MB by default): +
    +
  • Create a brand new memtable and log file and direct future updates here +
  • In the background: +
      +
    • Write the contents of the previous memtable to an sstable +
    • Discard the memtable +
    • Delete the old log file and the old memtable +
    • Add the new sstable to the young (level-0) level. +
    +
+ +

Compactions

+ +

+When the size of level L exceeds its limit, we compact it in a +background thread. The compaction picks a file from level L and all +overlapping files from the next level L+1. Note that if a level-L +file overlaps only part of a level-(L+1) file, the entire file at +level-(L+1) is used as an input to the compaction and will be +discarded after the compaction. Aside: because level-0 is special +(files in it may overlap each other), we treat compactions from +level-0 to level-1 specially: a level-0 compaction may pick more than +one level-0 file in case some of these files overlap each other. + +

+A compaction merges the contents of the picked files to produce a +sequence of level-(L+1) files. We switch to producing a new +level-(L+1) file after the current output file has reached the target +file size (2MB). We also switch to a new output file when the key +range of the current output file has grown enough to overlap more then +ten level-(L+2) files. This last rule ensures that a later compaction +of a level-(L+1) file will not pick up too much data from level-(L+2). + +

+The old files are discarded and the new files are added to the serving +state. + +

+Compactions for a particular level rotate through the key space. In +more detail, for each level L, we remember the ending key of the last +compaction at level L. The next compaction for level L will pick the +first file that starts after this key (wrapping around to the +beginning of the key space if there is no such file). + +

+Compactions drop overwritten values. They also drop deletion markers +if there are no higher numbered levels that contain a file whose range +overlaps the current key. + +

Timing

+ +Level-0 compactions will read up to four 1MB files from level-0, and +at worst all the level-1 files (10MB). I.e., we will read 14MB and +write 14MB. + +

+Other than the special level-0 compactions, we will pick one 2MB file +from level L. In the worst case, this will overlap ~ 12 files from +level L+1 (10 because level-(L+1) is ten times the size of level-L, +and another two at the boundaries since the file ranges at level-L +will usually not be aligned with the file ranges at level-L+1). The +compaction will therefore read 26MB and write 26MB. Assuming a disk +IO rate of 100MB/s (ballpark range for modern drives), the worst +compaction cost will be approximately 0.5 second. + +

+If we throttle the background writing to something small, say 10% of +the full 100MB/s speed, a compaction may take up to 5 seconds. If the +user is writing at 10MB/s, we might build up lots of level-0 files +(~50 to hold the 5*10MB). This may signficantly increase the cost of +reads due to the overhead of merging more files together on every +read. + +

+Solution 1: To reduce this problem, we might want to increase the log +switching threshold when the number of level-0 files is large. Though +the downside is that the larger this threshold, the more memory we will +need to hold the corresponding memtable. + +

+Solution 2: We might want to decrease write rate artificially when the +number of level-0 files goes up. + +

+Solution 3: We work on reducing the cost of very wide merges. +Perhaps most of the level-0 files will have their blocks sitting +uncompressed in the cache and we will only need to worry about the +O(N) complexity in the merging iterator. + +

Number of files

+ +Instead of always making 2MB files, we could make larger files for +larger levels to reduce the total file count, though at the expense of +more bursty compactions. Alternatively, we could shard the set of +files into multiple directories. + +

+An experiment on an ext3 filesystem on Feb 04, 2011 shows +the following timings to do 100K file opens in directories with +varying number of files: + + + + + +
Files in directoryMicroseconds to open a file
10009
1000010
10000016
+So maybe even the sharding is not necessary on modern filesystems? + +

Recovery

+ +
    +
  • Read CURRENT to find name of the latest committed MANIFEST +
  • Read the named MANIFEST file +
  • Clean up stale files +
  • We could open all sstables here, but it is probably better to be lazy... +
  • Convert log chunk to a new level-0 sstable +
  • Start directing new writes to a new log file with recovered sequence# +
+ +

Garbage collection of files

+ +DeleteObsoleteFiles() is called at the end of every +compaction and at the end of recovery. It finds the names of all +files in the database. It deletes all log files that are not the +current log file. It deletes all table files that are not referenced +from some level and are not the output of an active compaction. + + + diff --git a/src/leveldb/doc/index.html b/src/leveldb/doc/index.html new file mode 100644 index 0000000..3ed0ed9 --- /dev/null +++ b/src/leveldb/doc/index.html @@ -0,0 +1,549 @@ + + + + +Leveldb + + + +

Leveldb

+
Jeff Dean, Sanjay Ghemawat
+

+The leveldb library provides a persistent key value store. Keys and +values are arbitrary byte arrays. The keys are ordered within the key +value store according to a user-specified comparator function. + +

+

Opening A Database

+

+A leveldb database has a name which corresponds to a file system +directory. All of the contents of database are stored in this +directory. The following example shows how to open a database, +creating it if necessary: +

+

+  #include <assert>
+  #include "leveldb/db.h"
+
+  leveldb::DB* db;
+  leveldb::Options options;
+  options.create_if_missing = true;
+  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
+  assert(status.ok());
+  ...
+
+If you want to raise an error if the database already exists, add +the following line before the leveldb::DB::Open call: +
+  options.error_if_exists = true;
+
+

Status

+

+You may have noticed the leveldb::Status type above. Values of this +type are returned by most functions in leveldb that may encounter an +error. You can check if such a result is ok, and also print an +associated error message: +

+

+   leveldb::Status s = ...;
+   if (!s.ok()) cerr << s.ToString() << endl;
+
+

Closing A Database

+

+When you are done with a database, just delete the database object. +Example: +

+

+  ... open the db as described above ...
+  ... do something with db ...
+  delete db;
+
+

Reads And Writes

+

+The database provides Put, Delete, and Get methods to +modify/query the database. For example, the following code +moves the value stored under key1 to key2. +

+  std::string value;
+  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
+  if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
+  if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
+
+ +

Atomic Updates

+

+Note that if the process dies after the Put of key2 but before the +delete of key1, the same value may be left stored under multiple keys. +Such problems can be avoided by using the WriteBatch class to +atomically apply a set of updates: +

+

+  #include "leveldb/write_batch.h"
+  ...
+  std::string value;
+  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
+  if (s.ok()) {
+    leveldb::WriteBatch batch;
+    batch.Delete(key1);
+    batch.Put(key2, value);
+    s = db->Write(leveldb::WriteOptions(), &batch);
+  }
+
+The WriteBatch holds a sequence of edits to be made to the database, +and these edits within the batch are applied in order. Note that we +called Delete before Put so that if key1 is identical to key2, +we do not end up erroneously dropping the value entirely. +

+Apart from its atomicity benefits, WriteBatch may also be used to +speed up bulk updates by placing lots of individual mutations into the +same batch. + +

Synchronous Writes

+By default, each write to leveldb is asynchronous: it +returns after pushing the write from the process into the operating +system. The transfer from operating system memory to the underlying +persistent storage happens asynchronously. The sync flag +can be turned on for a particular write to make the write operation +not return until the data being written has been pushed all the way to +persistent storage. (On Posix systems, this is implemented by calling +either fsync(...) or fdatasync(...) or +msync(..., MS_SYNC) before the write operation returns.) +
+  leveldb::WriteOptions write_options;
+  write_options.sync = true;
+  db->Put(write_options, ...);
+
+Asynchronous writes are often more than a thousand times as fast as +synchronous writes. The downside of asynchronous writes is that a +crash of the machine may cause the last few updates to be lost. Note +that a crash of just the writing process (i.e., not a reboot) will not +cause any loss since even when sync is false, an update +is pushed from the process memory into the operating system before it +is considered done. + +

+Asynchronous writes can often be used safely. For example, when +loading a large amount of data into the database you can handle lost +updates by restarting the bulk load after a crash. A hybrid scheme is +also possible where every Nth write is synchronous, and in the event +of a crash, the bulk load is restarted just after the last synchronous +write finished by the previous run. (The synchronous write can update +a marker that describes where to restart on a crash.) + +

+WriteBatch provides an alternative to asynchronous writes. +Multiple updates may be placed in the same WriteBatch and +applied together using a synchronous write (i.e., +write_options.sync is set to true). The extra cost of +the synchronous write will be amortized across all of the writes in +the batch. + +

+

Concurrency

+

+A database may only be opened by one process at a time. +The leveldb implementation acquires a lock from the +operating system to prevent misuse. Within a single process, the +same leveldb::DB object may be safely shared by multiple +concurrent threads. I.e., different threads may write into or fetch +iterators or call Get on the same database without any +external synchronization (the leveldb implementation will +automatically do the required synchronization). However other objects +(like Iterator and WriteBatch) may require external synchronization. +If two threads share such an object, they must protect access to it +using their own locking protocol. More details are available in +the public header files. +

+

Iteration

+

+The following example demonstrates how to print all key,value pairs +in a database. +

+

+  leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
+  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;
+  }
+  assert(it->status().ok());  // Check for any errors found during the scan
+  delete it;
+
+The following variation shows how to process just the keys in the +range [start,limit): +

+

+  for (it->Seek(start);
+       it->Valid() && it->key().ToString() < limit;
+       it->Next()) {
+    ...
+  }
+
+You can also process entries in reverse order. (Caveat: reverse +iteration may be somewhat slower than forward iteration.) +

+

+  for (it->SeekToLast(); it->Valid(); it->Prev()) {
+    ...
+  }
+
+

Snapshots

+

+Snapshots provide consistent read-only views over the entire state of +the key-value store. ReadOptions::snapshot may be non-NULL to indicate +that a read should operate on a particular version of the DB state. +If ReadOptions::snapshot is NULL, the read will operate on an +implicit snapshot of the current state. +

+Snapshots are created by the DB::GetSnapshot() method: +

+

+  leveldb::ReadOptions options;
+  options.snapshot = db->GetSnapshot();
+  ... apply some updates to db ...
+  leveldb::Iterator* iter = db->NewIterator(options);
+  ... read using iter to view the state when the snapshot was created ...
+  delete iter;
+  db->ReleaseSnapshot(options.snapshot);
+
+Note that when a snapshot is no longer needed, it should be released +using the DB::ReleaseSnapshot interface. This allows the +implementation to get rid of state that was being maintained just to +support reading as of that snapshot. +

Slice

+

+The return value of the it->key() and it->value() calls above +are instances of the leveldb::Slice type. Slice is a simple +structure that contains a length and a pointer to an external byte +array. Returning a Slice is a cheaper alternative to returning a +std::string since we do not need to copy potentially large keys and +values. In addition, leveldb methods do not return null-terminated +C-style strings since leveldb keys and values are allowed to +contain '\0' bytes. +

+C++ strings and null-terminated C-style strings can be easily converted +to a Slice: +

+

+   leveldb::Slice s1 = "hello";
+
+   std::string str("world");
+   leveldb::Slice s2 = str;
+
+A Slice can be easily converted back to a C++ string: +
+   std::string str = s1.ToString();
+   assert(str == std::string("hello"));
+
+Be careful when using Slices since it is up to the caller to ensure that +the external byte array into which the Slice points remains live while +the Slice is in use. For example, the following is buggy: +

+

+   leveldb::Slice slice;
+   if (...) {
+     std::string str = ...;
+     slice = str;
+   }
+   Use(slice);
+
+When the if statement goes out of scope, str will be destroyed and the +backing storage for slice will disappear. +

+

Comparators

+

+The preceding examples used the default ordering function for key, +which orders bytes lexicographically. You can however supply a custom +comparator when opening a database. For example, suppose each +database key consists of two numbers and we should sort by the first +number, breaking ties by the second number. First, define a proper +subclass of leveldb::Comparator that expresses these rules: +

+

+  class TwoPartComparator : public leveldb::Comparator {
+   public:
+    // Three-way comparison function:
+    //   if a < b: negative result
+    //   if a > b: positive result
+    //   else: zero result
+    int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
+      int a1, a2, b1, b2;
+      ParseKey(a, &a1, &a2);
+      ParseKey(b, &b1, &b2);
+      if (a1 < b1) return -1;
+      if (a1 > b1) return +1;
+      if (a2 < b2) return -1;
+      if (a2 > b2) return +1;
+      return 0;
+    }
+
+    // Ignore the following methods for now:
+    const char* Name() const { return "TwoPartComparator"; }
+    void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
+    void FindShortSuccessor(std::string*) const { }
+  };
+
+Now create a database using this custom comparator: +

+

+  TwoPartComparator cmp;
+  leveldb::DB* db;
+  leveldb::Options options;
+  options.create_if_missing = true;
+  options.comparator = &cmp;
+  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
+  ...
+
+

Backwards compatibility

+

+The result of the comparator's Name method is attached to the +database when it is created, and is checked on every subsequent +database open. If the name changes, the leveldb::DB::Open call will +fail. Therefore, change the name if and only if the new key format +and comparison function are incompatible with existing databases, and +it is ok to discard the contents of all existing databases. +

+You can however still gradually evolve your key format over time with +a little bit of pre-planning. For example, you could store a version +number at the end of each key (one byte should suffice for most uses). +When you wish to switch to a new key format (e.g., adding an optional +third part to the keys processed by TwoPartComparator), +(a) keep the same comparator name (b) increment the version number +for new keys (c) change the comparator function so it uses the +version numbers found in the keys to decide how to interpret them. +

+

Performance

+

+Performance can be tuned by changing the default values of the +types defined in include/leveldb/options.h. + +

+

Block size

+

+leveldb groups adjacent keys together into the same block and such a +block is the unit of transfer to and from persistent storage. The +default block size is approximately 4096 uncompressed bytes. +Applications that mostly do bulk scans over the contents of the +database may wish to increase this size. Applications that do a lot +of point reads of small values may wish to switch to a smaller block +size if performance measurements indicate an improvement. There isn't +much benefit in using blocks smaller than one kilobyte, or larger than +a few megabytes. Also note that compression will be more effective +with larger block sizes. +

+

Compression

+

+Each block is individually compressed before being written to +persistent storage. Compression is on by default since the default +compression method is very fast, and is automatically disabled for +uncompressible data. In rare cases, applications may want to disable +compression entirely, but should only do so if benchmarks show a +performance improvement: +

+

+  leveldb::Options options;
+  options.compression = leveldb::kNoCompression;
+  ... leveldb::DB::Open(options, name, ...) ....
+
+

Cache

+

+The contents of the database are stored in a set of files in the +filesystem and each file stores a sequence of compressed blocks. If +options.cache is non-NULL, it is used to cache frequently used +uncompressed block contents. +

+

+  #include "leveldb/cache.h"
+
+  leveldb::Options options;
+  options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
+  leveldb::DB* db;
+  leveldb::DB::Open(options, name, &db);
+  ... use the db ...
+  delete db
+  delete options.cache;
+
+Note that the cache holds uncompressed data, and therefore it should +be sized according to application level data sizes, without any +reduction from compression. (Caching of compressed blocks is left to +the operating system buffer cache, or any custom Env +implementation provided by the client.) +

+When performing a bulk read, the application may wish to disable +caching so that the data processed by the bulk read does not end up +displacing most of the cached contents. A per-iterator option can be +used to achieve this: +

+

+  leveldb::ReadOptions options;
+  options.fill_cache = false;
+  leveldb::Iterator* it = db->NewIterator(options);
+  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+    ...
+  }
+
+

Key Layout

+

+Note that the unit of disk transfer and caching is a block. Adjacent +keys (according to the database sort order) will usually be placed in +the same block. Therefore the application can improve its performance +by placing keys that are accessed together near each other and placing +infrequently used keys in a separate region of the key space. +

+For example, suppose we are implementing a simple file system on top +of leveldb. The types of entries we might wish to store are: +

+

+   filename -> permission-bits, length, list of file_block_ids
+   file_block_id -> data
+
+We might want to prefix filename keys with one letter (say '/') and the +file_block_id keys with a different letter (say '0') so that scans +over just the metadata do not force us to fetch and cache bulky file +contents. +

+

Filters

+

+Because of the way leveldb data is organized on disk, +a single Get() call may involve multiple reads from disk. +The optional FilterPolicy mechanism can be used to reduce +the number of disk reads substantially. +

+   leveldb::Options options;
+   options.filter_policy = NewBloomFilterPolicy(10);
+   leveldb::DB* db;
+   leveldb::DB::Open(options, "/tmp/testdb", &db);
+   ... use the database ...
+   delete db;
+   delete options.filter_policy;
+
+The preceding code associates a +Bloom filter +based filtering policy with the database. Bloom filter based +filtering relies on keeping some number of bits of data in memory per +key (in this case 10 bits per key since that is the argument we passed +to NewBloomFilterPolicy). This filter will reduce the number of unnecessary +disk reads needed for Get() calls by a factor of +approximately a 100. Increasing the bits per key will lead to a +larger reduction at the cost of more memory usage. We recommend that +applications whose working set does not fit in memory and that do a +lot of random reads set a filter policy. +

+If you are using a custom comparator, you should ensure that the filter +policy you are using is compatible with your comparator. For example, +consider a comparator that ignores trailing spaces when comparing keys. +NewBloomFilterPolicy must not be used with such a comparator. +Instead, the application should provide a custom filter policy that +also ignores trailing spaces. For example: +

+  class CustomFilterPolicy : public leveldb::FilterPolicy {
+   private:
+    FilterPolicy* builtin_policy_;
+   public:
+    CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) { }
+    ~CustomFilterPolicy() { delete builtin_policy_; }
+
+    const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
+
+    void CreateFilter(const Slice* keys, int n, std::string* dst) const {
+      // Use builtin bloom filter code after removing trailing spaces
+      std::vector<Slice> trimmed(n);
+      for (int i = 0; i < n; i++) {
+        trimmed[i] = RemoveTrailingSpaces(keys[i]);
+      }
+      return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
+    }
+
+    bool KeyMayMatch(const Slice& key, const Slice& filter) const {
+      // Use builtin bloom filter code after removing trailing spaces
+      return builtin_policy_->KeyMayMatch(RemoveTrailingSpaces(key), filter);
+    }
+  };
+
+

+Advanced applications may provide a filter policy that does not use +a bloom filter but uses some other mechanism for summarizing a set +of keys. See leveldb/filter_policy.h for detail. +

+

Checksums

+

+leveldb associates checksums with all data it stores in the file system. +There are two separate controls provided over how aggressively these +checksums are verified: +

+

    +
  • ReadOptions::verify_checksums may be set to true to force + checksum verification of all data that is read from the file system on + behalf of a particular read. By default, no such verification is + done. +

    +

  • Options::paranoid_checks may be set to true before opening a + database to make the database implementation raise an error as soon as + it detects an internal corruption. Depending on which portion of the + database has been corrupted, the error may be raised when the database + is opened, or later by another database operation. By default, + paranoid checking is off so that the database can be used even if + parts of its persistent storage have been corrupted. +

    + If a database is corrupted (perhaps it cannot be opened when + paranoid checking is turned on), the leveldb::RepairDB function + may be used to recover as much of the data as possible +

    +

+

Approximate Sizes

+

+The GetApproximateSizes method can used to get the approximate +number of bytes of file system space used by one or more key ranges. +

+

+   leveldb::Range ranges[2];
+   ranges[0] = leveldb::Range("a", "c");
+   ranges[1] = leveldb::Range("x", "z");
+   uint64_t sizes[2];
+   leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
+
+The preceding call will set sizes[0] to the approximate number of +bytes of file system space used by the key range [a..c) and +sizes[1] to the approximate number of bytes used by the key range +[x..z). +

+

Environment

+

+All file operations (and other operating system calls) issued by the +leveldb implementation are routed through a leveldb::Env object. +Sophisticated clients may wish to provide their own Env +implementation to get better control. For example, an application may +introduce artificial delays in the file IO paths to limit the impact +of leveldb on other activities in the system. +

+

+  class SlowEnv : public leveldb::Env {
+    .. implementation of the Env interface ...
+  };
+
+  SlowEnv env;
+  leveldb::Options options;
+  options.env = &env;
+  Status s = leveldb::DB::Open(options, ...);
+
+

Porting

+

+leveldb may be ported to a new platform by providing platform +specific implementations of the types/methods/functions exported by +leveldb/port/port.h. See leveldb/port/port_example.h for more +details. +

+In addition, the new platform may need a new default leveldb::Env +implementation. See leveldb/util/env_posix.h for an example. + +

Other Information

+ +

+Details about the leveldb implementation may be found in +the following documents: +

+ + + diff --git a/src/leveldb/doc/log_format.txt b/src/leveldb/doc/log_format.txt new file mode 100644 index 0000000..5228f62 --- /dev/null +++ b/src/leveldb/doc/log_format.txt @@ -0,0 +1,75 @@ +The log file contents are a sequence of 32KB blocks. The only +exception is that the tail of the file may contain a partial block. + +Each block consists of a sequence of records: + block := record* trailer? + record := + checksum: uint32 // crc32c of type and data[] ; little-endian + length: uint16 // little-endian + type: uint8 // One of FULL, FIRST, MIDDLE, LAST + data: uint8[length] + +A record never starts within the last six bytes of a block (since it +won't fit). Any leftover bytes here form the trailer, which must +consist entirely of zero bytes and must be skipped by readers. + +Aside: if exactly seven bytes are left in the current block, and a new +non-zero length record is added, the writer must emit a FIRST record +(which contains zero bytes of user data) to fill up the trailing seven +bytes of the block and then emit all of the user data in subsequent +blocks. + +More types may be added in the future. Some Readers may skip record +types they do not understand, others may report that some data was +skipped. + +FULL == 1 +FIRST == 2 +MIDDLE == 3 +LAST == 4 + +The FULL record contains the contents of an entire user record. + +FIRST, MIDDLE, LAST are types used for user records that have been +split into multiple fragments (typically because of block boundaries). +FIRST is the type of the first fragment of a user record, LAST is the +type of the last fragment of a user record, and MID is the type of all +interior fragments of a user record. + +Example: consider a sequence of user records: + A: length 1000 + B: length 97270 + C: length 8000 +A will be stored as a FULL record in the first block. + +B will be split into three fragments: first fragment occupies the rest +of the first block, second fragment occupies the entirety of the +second block, and the third fragment occupies a prefix of the third +block. This will leave six bytes free in the third block, which will +be left empty as the trailer. + +C will be stored as a FULL record in the fourth block. + +=================== + +Some benefits over the recordio format: + +(1) We do not need any heuristics for resyncing - just go to next +block boundary and scan. If there is a corruption, skip to the next +block. As a side-benefit, we do not get confused when part of the +contents of one log file are embedded as a record inside another log +file. + +(2) Splitting at approximate boundaries (e.g., for mapreduce) is +simple: find the next block boundary and skip records until we +hit a FULL or FIRST record. + +(3) We do not need extra buffering for large records. + +Some downsides compared to recordio format: + +(1) No packing of tiny records. This could be fixed by adding a new +record type, so it is a shortcoming of the current implementation, +not necessarily the format. + +(2) No compression. Again, this could be fixed by adding new record types. diff --git a/src/leveldb/doc/table_format.txt b/src/leveldb/doc/table_format.txt new file mode 100644 index 0000000..ca8f9b4 --- /dev/null +++ b/src/leveldb/doc/table_format.txt @@ -0,0 +1,104 @@ +File format +=========== + + + [data block 1] + [data block 2] + ... + [data block N] + [meta block 1] + ... + [meta block K] + [metaindex block] + [index block] + [Footer] (fixed size; starts at file_size - sizeof(Footer)) + + +The file contains internal pointers. Each such pointer is called +a BlockHandle and contains the following information: + offset: varint64 + size: varint64 +See https://developers.google.com/protocol-buffers/docs/encoding#varints +for an explanation of varint64 format. + +(1) The sequence of key/value pairs in the file are stored in sorted +order and partitioned into a sequence of data blocks. These blocks +come one after another at the beginning of the file. Each data block +is formatted according to the code in block_builder.cc, and then +optionally compressed. + +(2) After the data blocks we store a bunch of meta blocks. The +supported meta block types are described below. More meta block types +may be added in the future. Each meta block is again formatted using +block_builder.cc and then optionally compressed. + +(3) A "metaindex" block. It contains one entry for every other meta +block where the key is the name of the meta block and the value is a +BlockHandle pointing to that meta block. + +(4) An "index" block. This block contains one entry per data block, +where the key is a string >= last key in that data block and before +the first key in the successive data block. The value is the +BlockHandle for the data block. + +(6) At the very end of the file is a fixed length footer that contains +the BlockHandle of the metaindex and index blocks as well as a magic number. + metaindex_handle: char[p]; // Block handle for metaindex + index_handle: char[q]; // Block handle for index + padding: char[40-p-q]; // zeroed bytes to make fixed length + // (40==2*BlockHandle::kMaxEncodedLength) + magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) + +"filter" Meta Block +------------------- + +If a "FilterPolicy" was specified when the database was opened, a +filter block is stored in each table. The "metaindex" block contains +an entry that maps from "filter." to the BlockHandle for the filter +block where "" is the string returned by the filter policy's +"Name()" method. + +The filter block stores a sequence of filters, where filter i contains +the output of FilterPolicy::CreateFilter() on all keys that are stored +in a block whose file offset falls within the range + + [ i*base ... (i+1)*base-1 ] + +Currently, "base" is 2KB. So for example, if blocks X and Y start in +the range [ 0KB .. 2KB-1 ], all of the keys in X and Y will be +converted to a filter by calling FilterPolicy::CreateFilter(), and the +resulting filter will be stored as the first filter in the filter +block. + +The filter block is formatted as follows: + + [filter 0] + [filter 1] + [filter 2] + ... + [filter N-1] + + [offset of filter 0] : 4 bytes + [offset of filter 1] : 4 bytes + [offset of filter 2] : 4 bytes + ... + [offset of filter N-1] : 4 bytes + + [offset of beginning of offset array] : 4 bytes + lg(base) : 1 byte + +The offset array at the end of the filter block allows efficient +mapping from a data block offset to the corresponding filter. + +"stats" Meta Block +------------------ + +This meta block contains a bunch of stats. The key is the name +of the statistic. The value contains the statistic. +TODO(postrelease): record following stats. + data size + index size + key size (uncompressed) + value size (uncompressed) + number of entries + number of data blocks diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc new file mode 100644 index 0000000..5879de1 --- /dev/null +++ b/src/leveldb/helpers/memenv/memenv.cc @@ -0,0 +1,384 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "helpers/memenv/memenv.h" + +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "port/port.h" +#include "util/mutexlock.h" +#include +#include +#include +#include + +namespace leveldb { + +namespace { + +class FileState { + public: + // FileStates are reference counted. The initial reference count is zero + // and the caller must call Ref() at least once. + FileState() : refs_(0), size_(0) {} + + // Increase the reference count. + void Ref() { + MutexLock lock(&refs_mutex_); + ++refs_; + } + + // Decrease the reference count. Delete if this is the last reference. + void Unref() { + bool do_delete = false; + + { + MutexLock lock(&refs_mutex_); + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + do_delete = true; + } + } + + if (do_delete) { + delete this; + } + } + + uint64_t Size() const { return size_; } + + Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { + if (offset > size_) { + return Status::IOError("Offset greater than file size."); + } + const uint64_t available = size_ - offset; + if (n > available) { + n = available; + } + if (n == 0) { + *result = Slice(); + return Status::OK(); + } + + size_t block = offset / kBlockSize; + size_t block_offset = offset % kBlockSize; + + if (n <= kBlockSize - block_offset) { + // The requested bytes are all in the first block. + *result = Slice(blocks_[block] + block_offset, n); + return Status::OK(); + } + + size_t bytes_to_copy = n; + char* dst = scratch; + + while (bytes_to_copy > 0) { + size_t avail = kBlockSize - block_offset; + if (avail > bytes_to_copy) { + avail = bytes_to_copy; + } + memcpy(dst, blocks_[block] + block_offset, avail); + + bytes_to_copy -= avail; + dst += avail; + block++; + block_offset = 0; + } + + *result = Slice(scratch, n); + return Status::OK(); + } + + Status Append(const Slice& data) { + const char* src = data.data(); + size_t src_len = data.size(); + + while (src_len > 0) { + size_t avail; + size_t offset = size_ % kBlockSize; + + if (offset != 0) { + // There is some room in the last block. + avail = kBlockSize - offset; + } else { + // No room in the last block; push new one. + blocks_.push_back(new char[kBlockSize]); + avail = kBlockSize; + } + + if (avail > src_len) { + avail = src_len; + } + memcpy(blocks_.back() + offset, src, avail); + src_len -= avail; + src += avail; + size_ += avail; + } + + return Status::OK(); + } + + private: + // Private since only Unref() should be used to delete it. + ~FileState() { + for (std::vector::iterator i = blocks_.begin(); i != blocks_.end(); + ++i) { + delete [] *i; + } + } + + // No copying allowed. + FileState(const FileState&); + void operator=(const FileState&); + + port::Mutex refs_mutex_; + int refs_; // Protected by refs_mutex_; + + // The following fields are not protected by any mutex. They are only mutable + // while the file is being written, and concurrent access is not allowed + // to writable files. + std::vector blocks_; + uint64_t size_; + + enum { kBlockSize = 8 * 1024 }; +}; + +class SequentialFileImpl : public SequentialFile { + public: + explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) { + file_->Ref(); + } + + ~SequentialFileImpl() { + file_->Unref(); + } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s = file_->Read(pos_, n, result, scratch); + if (s.ok()) { + pos_ += result->size(); + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (pos_ > file_->Size()) { + return Status::IOError("pos_ > file_->Size()"); + } + const size_t available = file_->Size() - pos_; + if (n > available) { + n = available; + } + pos_ += n; + return Status::OK(); + } + + private: + FileState* file_; + size_t pos_; +}; + +class RandomAccessFileImpl : public RandomAccessFile { + public: + explicit RandomAccessFileImpl(FileState* file) : file_(file) { + file_->Ref(); + } + + ~RandomAccessFileImpl() { + file_->Unref(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + return file_->Read(offset, n, result, scratch); + } + + private: + FileState* file_; +}; + +class WritableFileImpl : public WritableFile { + public: + WritableFileImpl(FileState* file) : file_(file) { + file_->Ref(); + } + + ~WritableFileImpl() { + file_->Unref(); + } + + virtual Status Append(const Slice& data) { + return file_->Append(data); + } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + private: + FileState* file_; +}; + +class NoOpLogger : public Logger { + public: + virtual void Logv(const char* format, va_list ap) { } +}; + +class InMemoryEnv : public EnvWrapper { + public: + explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { } + + virtual ~InMemoryEnv() { + for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ + i->second->Unref(); + } + } + + // Partial implementation of the Env interface. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + *result = NULL; + return Status::IOError(fname, "File not found"); + } + + *result = new SequentialFileImpl(file_map_[fname]); + return Status::OK(); + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + *result = NULL; + return Status::IOError(fname, "File not found"); + } + + *result = new RandomAccessFileImpl(file_map_[fname]); + return Status::OK(); + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) != file_map_.end()) { + DeleteFileInternal(fname); + } + + FileState* file = new FileState(); + file->Ref(); + file_map_[fname] = file; + + *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(); + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + MutexLock lock(&mutex_); + result->clear(); + + for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ + const std::string& filename = i->first; + + if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' && + Slice(filename).starts_with(Slice(dir))) { + result->push_back(filename.substr(dir.size() + 1)); + } + } + + return Status::OK(); + } + + void DeleteFileInternal(const std::string& fname) { + if (file_map_.find(fname) == file_map_.end()) { + return; + } + + file_map_[fname]->Unref(); + file_map_.erase(fname); + } + + virtual Status DeleteFile(const std::string& fname) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + return Status::IOError(fname, "File not found"); + } + + DeleteFileInternal(fname); + return Status::OK(); + } + + virtual Status CreateDir(const std::string& dirname) { + return Status::OK(); + } + + virtual Status DeleteDir(const std::string& dirname) { + return Status::OK(); + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + return Status::IOError(fname, "File not found"); + } + + *file_size = file_map_[fname]->Size(); + return Status::OK(); + } + + virtual Status RenameFile(const std::string& src, + const std::string& target) { + MutexLock lock(&mutex_); + if (file_map_.find(src) == file_map_.end()) { + return Status::IOError(src, "File not found"); + } + + DeleteFileInternal(target); + file_map_[target] = file_map_[src]; + file_map_.erase(src); + return Status::OK(); + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = new FileLock; + return Status::OK(); + } + + virtual Status UnlockFile(FileLock* lock) { + delete lock; + return Status::OK(); + } + + virtual Status GetTestDirectory(std::string* path) { + *path = "/test"; + return Status::OK(); + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + *result = new NoOpLogger; + return Status::OK(); + } + + private: + // Map from filenames to FileState objects, representing a simple file system. + typedef std::map FileSystem; + port::Mutex mutex_; + FileSystem file_map_; // Protected by mutex_. +}; + +} // namespace + +Env* NewMemEnv(Env* base_env) { + return new InMemoryEnv(base_env); +} + +} // namespace leveldb diff --git a/src/leveldb/helpers/memenv/memenv.h b/src/leveldb/helpers/memenv/memenv.h new file mode 100644 index 0000000..03b88de --- /dev/null +++ b/src/leveldb/helpers/memenv/memenv.h @@ -0,0 +1,20 @@ +// 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_HELPERS_MEMENV_MEMENV_H_ +#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ + +namespace leveldb { + +class Env; + +// Returns a new environment that stores its data in memory and delegates +// all non-file-storage tasks to base_env. The caller must delete the result +// when it is no longer needed. +// *base_env must remain live while the result is in use. +Env* NewMemEnv(Env* base_env); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ diff --git a/src/leveldb/helpers/memenv/memenv_test.cc b/src/leveldb/helpers/memenv/memenv_test.cc new file mode 100644 index 0000000..a44310f --- /dev/null +++ b/src/leveldb/helpers/memenv/memenv_test.cc @@ -0,0 +1,232 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "helpers/memenv/memenv.h" + +#include "db/db_impl.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "util/testharness.h" +#include +#include + +namespace leveldb { + +class MemEnvTest { + public: + Env* env_; + + MemEnvTest() + : env_(NewMemEnv(Env::Default())) { + } + ~MemEnvTest() { + delete env_; + } +}; + +TEST(MemEnvTest, Basics) { + uint64_t file_size; + WritableFile* writable_file; + std::vector children; + + ASSERT_OK(env_->CreateDir("/dir")); + + // Check that the directory is empty. + ASSERT_TRUE(!env_->FileExists("/dir/non_existent")); + ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok()); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(0, children.size()); + + // Create a file. + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + delete writable_file; + + // Check that the file exists. + ASSERT_TRUE(env_->FileExists("/dir/f")); + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(0, file_size); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(1, children.size()); + ASSERT_EQ("f", children[0]); + + // Write to the file. + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("abc")); + delete writable_file; + + // Check for expected size. + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(3, file_size); + + // Check that renaming works. + ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); + ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g")); + 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); + + // Check that opening non-existent file fails. + SequentialFile* seq_file; + RandomAccessFile* rand_file; + ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok()); + ASSERT_TRUE(!seq_file); + ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok()); + ASSERT_TRUE(!rand_file); + + // Check that deleting works. + ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok()); + ASSERT_OK(env_->DeleteFile("/dir/g")); + ASSERT_TRUE(!env_->FileExists("/dir/g")); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(0, children.size()); + ASSERT_OK(env_->DeleteDir("/dir")); +} + +TEST(MemEnvTest, ReadWrite) { + WritableFile* writable_file; + SequentialFile* seq_file; + RandomAccessFile* rand_file; + Slice result; + char scratch[100]; + + ASSERT_OK(env_->CreateDir("/dir")); + + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("hello ")); + ASSERT_OK(writable_file->Append("world")); + delete writable_file; + + // Read sequentially. + ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); + ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello". + ASSERT_EQ(0, result.compare("hello")); + ASSERT_OK(seq_file->Skip(1)); + ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world". + ASSERT_EQ(0, result.compare("world")); + ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF. + ASSERT_EQ(0, result.size()); + ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file. + ASSERT_OK(seq_file->Read(1000, &result, scratch)); + ASSERT_EQ(0, result.size()); + delete seq_file; + + // Random reads. + ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file)); + ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world". + ASSERT_EQ(0, result.compare("world")); + ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello". + ASSERT_EQ(0, result.compare("hello")); + ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d". + ASSERT_EQ(0, result.compare("d")); + + // Too high offset. + ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok()); + delete rand_file; +} + +TEST(MemEnvTest, Locks) { + FileLock* lock; + + // These are no-ops, but we test they return success. + ASSERT_OK(env_->LockFile("some file", &lock)); + ASSERT_OK(env_->UnlockFile(lock)); +} + +TEST(MemEnvTest, Misc) { + std::string test_dir; + ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_TRUE(!test_dir.empty()); + + WritableFile* writable_file; + ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file)); + + // These are no-ops, but we test they return success. + ASSERT_OK(writable_file->Sync()); + ASSERT_OK(writable_file->Flush()); + ASSERT_OK(writable_file->Close()); + delete writable_file; +} + +TEST(MemEnvTest, LargeWrite) { + const size_t kWriteSize = 300 * 1024; + char* scratch = new char[kWriteSize * 2]; + + std::string write_data; + for (size_t i = 0; i < kWriteSize; ++i) { + write_data.append(1, static_cast(i)); + } + + WritableFile* writable_file; + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("foo")); + ASSERT_OK(writable_file->Append(write_data)); + delete writable_file; + + SequentialFile* seq_file; + Slice result; + ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); + ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo". + ASSERT_EQ(0, result.compare("foo")); + + size_t read = 0; + std::string read_data; + while (read < kWriteSize) { + ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch)); + read_data.append(result.data(), result.size()); + read += result.size(); + } + ASSERT_TRUE(write_data == read_data); + delete seq_file; + delete [] scratch; +} + +TEST(MemEnvTest, DBTest) { + Options options; + options.create_if_missing = true; + options.env = env_; + DB* db; + + const Slice keys[] = {Slice("aaa"), Slice("bbb"), Slice("ccc")}; + const Slice vals[] = {Slice("foo"), Slice("bar"), Slice("baz")}; + + ASSERT_OK(DB::Open(options, "/dir/db", &db)); + for (size_t i = 0; i < 3; ++i) { + ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i])); + } + + for (size_t i = 0; i < 3; ++i) { + std::string res; + ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); + ASSERT_TRUE(res == vals[i]); + } + + Iterator* iterator = db->NewIterator(ReadOptions()); + iterator->SeekToFirst(); + for (size_t i = 0; i < 3; ++i) { + ASSERT_TRUE(iterator->Valid()); + ASSERT_TRUE(keys[i] == iterator->key()); + ASSERT_TRUE(vals[i] == iterator->value()); + iterator->Next(); + } + ASSERT_TRUE(!iterator->Valid()); + delete iterator; + + DBImpl* dbi = reinterpret_cast(db); + ASSERT_OK(dbi->TEST_CompactMemTable()); + + for (size_t i = 0; i < 3; ++i) { + std::string res; + ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); + ASSERT_TRUE(res == vals[i]); + } + + delete db; +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/include/leveldb/c.h b/src/leveldb/include/leveldb/c.h new file mode 100644 index 0000000..1fa5886 --- /dev/null +++ b/src/leveldb/include/leveldb/c.h @@ -0,0 +1,291 @@ +/* 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. + + C bindings for leveldb. May be useful as a stable ABI that can be + used by programs that keep leveldb in a shared library, or for + a JNI api. + + Does not support: + . getters for the option types + . custom comparators that implement key shortening + . capturing post-write-snapshot + . custom iter, db, env, cache implementations using just the C bindings + + Some conventions: + + (1) We expose just opaque struct pointers and functions to clients. + This allows us to change internal representations without having to + recompile clients. + + (2) For simplicity, there is no equivalent to the Slice type. Instead, + the caller has to pass the pointer and length as separate + arguments. + + (3) Errors are represented by a null-terminated c string. NULL + means no error. All operations that can raise an error are passed + a "char** errptr" as the last argument. One of the following must + be true on entry: + *errptr == NULL + *errptr points to a malloc()ed null-terminated error message + (On Windows, *errptr must have been malloc()-ed by this library.) + On success, a leveldb routine leaves *errptr unchanged. + On failure, leveldb frees the old value of *errptr and + set *errptr to a malloc()ed error message. + + (4) Bools have the type unsigned char (0 == false; rest == true) + + (5) All of the pointer arguments must be non-NULL. +*/ + +#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ +#define STORAGE_LEVELDB_INCLUDE_C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* Exported types */ + +typedef struct leveldb_t leveldb_t; +typedef struct leveldb_cache_t leveldb_cache_t; +typedef struct leveldb_comparator_t leveldb_comparator_t; +typedef struct leveldb_env_t leveldb_env_t; +typedef struct leveldb_filelock_t leveldb_filelock_t; +typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; +typedef struct leveldb_iterator_t leveldb_iterator_t; +typedef struct leveldb_logger_t leveldb_logger_t; +typedef struct leveldb_options_t leveldb_options_t; +typedef struct leveldb_randomfile_t leveldb_randomfile_t; +typedef struct leveldb_readoptions_t leveldb_readoptions_t; +typedef struct leveldb_seqfile_t leveldb_seqfile_t; +typedef struct leveldb_snapshot_t leveldb_snapshot_t; +typedef struct leveldb_writablefile_t leveldb_writablefile_t; +typedef struct leveldb_writebatch_t leveldb_writebatch_t; +typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; + +/* DB operations */ + +extern leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_close(leveldb_t* db); + +extern void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr); + +extern void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr); + +extern void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr); + +/* Returns NULL if not found. A malloc()ed array otherwise. + Stores the length of the array in *vallen. */ +extern char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr); + +extern leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options); + +extern const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db); + +extern void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot); + +/* Returns NULL if property name is unknown. + Else returns a pointer to a malloc()-ed null-terminated value. */ +extern char* leveldb_property_value( + leveldb_t* db, + const char* propname); + +extern void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes); + +extern void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len); + +/* Management operations */ + +extern void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +/* Iterator */ + +extern void leveldb_iter_destroy(leveldb_iterator_t*); +extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*); +extern void leveldb_iter_seek_to_first(leveldb_iterator_t*); +extern void leveldb_iter_seek_to_last(leveldb_iterator_t*); +extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen); +extern void leveldb_iter_next(leveldb_iterator_t*); +extern void leveldb_iter_prev(leveldb_iterator_t*); +extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen); +extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen); +extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr); + +/* Write batch */ + +extern leveldb_writebatch_t* leveldb_writebatch_create(); +extern void leveldb_writebatch_destroy(leveldb_writebatch_t*); +extern void leveldb_writebatch_clear(leveldb_writebatch_t*); +extern void leveldb_writebatch_put( + leveldb_writebatch_t*, + const char* key, size_t klen, + const char* val, size_t vlen); +extern void leveldb_writebatch_delete( + leveldb_writebatch_t*, + const char* key, size_t klen); +extern void leveldb_writebatch_iterate( + leveldb_writebatch_t*, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)); + +/* Options */ + +extern leveldb_options_t* leveldb_options_create(); +extern void leveldb_options_destroy(leveldb_options_t*); +extern void leveldb_options_set_comparator( + leveldb_options_t*, + leveldb_comparator_t*); +extern void leveldb_options_set_filter_policy( + leveldb_options_t*, + leveldb_filterpolicy_t*); +extern void leveldb_options_set_create_if_missing( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_error_if_exists( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_paranoid_checks( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); +extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*); +extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_max_open_files(leveldb_options_t*, int); +extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*); +extern void leveldb_options_set_block_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int); + +enum { + leveldb_no_compression = 0, + leveldb_snappy_compression = 1 +}; +extern void leveldb_options_set_compression(leveldb_options_t*, int); + +/* Comparator */ + +extern leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)); +extern void leveldb_comparator_destroy(leveldb_comparator_t*); + +/* Filter policy */ + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)); +extern void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( + int bits_per_key); + +/* Read options */ + +extern leveldb_readoptions_t* leveldb_readoptions_create(); +extern void leveldb_readoptions_destroy(leveldb_readoptions_t*); +extern void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t*, + unsigned char); +extern void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t*, unsigned char); +extern void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t*, + const leveldb_snapshot_t*); + +/* Write options */ + +extern leveldb_writeoptions_t* leveldb_writeoptions_create(); +extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); +extern void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t*, unsigned char); + +/* Cache */ + +extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); +extern void leveldb_cache_destroy(leveldb_cache_t* cache); + +/* Env */ + +extern leveldb_env_t* leveldb_create_default_env(); +extern void leveldb_env_destroy(leveldb_env_t*); + +/* Utility */ + +/* Calls free(ptr). + REQUIRES: ptr was malloc()-ed and returned by one of the routines + in this file. Note that in certain cases (typically on Windows), you + may need to call this routine instead of free(ptr) to dispose of + malloc()-ed memory returned by this library. */ +extern void leveldb_free(void* ptr); + +/* Return the major version number for this release. */ +extern int leveldb_major_version(); + +/* Return the minor version number for this release. */ +extern int leveldb_minor_version(); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/src/leveldb/include/leveldb/cache.h b/src/leveldb/include/leveldb/cache.h new file mode 100644 index 0000000..5e3b476 --- /dev/null +++ b/src/leveldb/include/leveldb/cache.h @@ -0,0 +1,99 @@ +// 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. +// +// A Cache is an interface that maps keys to values. It has internal +// synchronization and may be safely accessed concurrently from +// multiple threads. It may automatically evict entries to make room +// for new entries. Values have a specified charge against the cache +// capacity. For example, a cache where the values are variable +// length strings, may use the length of the string as the charge for +// the string. +// +// A builtin cache implementation with a least-recently-used eviction +// policy is provided. Clients may use their own implementations if +// they want something more sophisticated (like scan-resistance, a +// custom eviction policy, variable cache sizing, etc.) + +#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ +#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Cache; + +// Create a new cache with a fixed size capacity. This implementation +// of Cache uses a least-recently-used eviction policy. +extern Cache* NewLRUCache(size_t capacity); + +class Cache { + public: + Cache() { } + + // Destroys all existing entries by calling the "deleter" + // function that was passed to the constructor. + virtual ~Cache(); + + // Opaque handle to an entry stored in the cache. + struct Handle { }; + + // Insert a mapping from key->value into the cache and assign it + // the specified charge against the total cache capacity. + // + // Returns a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + // + // When the inserted entry is no longer needed, the key and + // value will be passed to "deleter". + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) = 0; + + // If the cache has no mapping for "key", returns NULL. + // + // Else return a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + virtual Handle* Lookup(const Slice& key) = 0; + + // Release a mapping returned by a previous Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void Release(Handle* handle) = 0; + + // Return the value encapsulated in a handle returned by a + // successful Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void* Value(Handle* handle) = 0; + + // If the cache contains entry for key, erase it. Note that the + // underlying entry will be kept around until all existing handles + // to it have been released. + virtual void Erase(const Slice& key) = 0; + + // Return a new numeric id. May be used by multiple clients who are + // sharing the same cache to partition the key space. Typically the + // client will allocate a new id at startup and prepend the id to + // its cache keys. + virtual uint64_t NewId() = 0; + + private: + void LRU_Remove(Handle* e); + void LRU_Append(Handle* e); + void Unref(Handle* e); + + struct Rep; + Rep* rep_; + + // No copying allowed + Cache(const Cache&); + void operator=(const Cache&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CACHE_H_ diff --git a/src/leveldb/include/leveldb/comparator.h b/src/leveldb/include/leveldb/comparator.h new file mode 100644 index 0000000..556b984 --- /dev/null +++ b/src/leveldb/include/leveldb/comparator.h @@ -0,0 +1,63 @@ +// 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_INCLUDE_COMPARATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ + +#include + +namespace leveldb { + +class Slice; + +// A Comparator object provides a total order across slices that are +// used as keys in an sstable or a database. A Comparator implementation +// must be thread-safe since leveldb may invoke its methods concurrently +// from multiple threads. +class Comparator { + public: + virtual ~Comparator(); + + // Three-way comparison. Returns value: + // < 0 iff "a" < "b", + // == 0 iff "a" == "b", + // > 0 iff "a" > "b" + virtual int Compare(const Slice& a, const Slice& b) const = 0; + + // The name of the comparator. Used to check for comparator + // mismatches (i.e., a DB created with one comparator is + // accessed using a different comparator. + // + // The client of this package should switch to a new name whenever + // the comparator implementation changes in a way that will cause + // the relative ordering of any two keys to change. + // + // Names starting with "leveldb." are reserved and should not be used + // by any clients of this package. + virtual const char* Name() const = 0; + + // Advanced functions: these are used to reduce the space requirements + // for internal data structures like index blocks. + + // If *start < limit, changes *start to a short string in [start,limit). + // Simple comparator implementations may return with *start unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const = 0; + + // Changes *key to a short string >= *key. + // Simple comparator implementations may return with *key unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortSuccessor(std::string* key) const = 0; +}; + +// Return a builtin comparator that uses lexicographic byte-wise +// ordering. The result remains the property of this module and +// must not be deleted. +extern const Comparator* BytewiseComparator(); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h new file mode 100644 index 0000000..57c00a5 --- /dev/null +++ b/src/leveldb/include/leveldb/db.h @@ -0,0 +1,161 @@ +// 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_INCLUDE_DB_H_ +#define STORAGE_LEVELDB_INCLUDE_DB_H_ + +#include +#include +#include "leveldb/iterator.h" +#include "leveldb/options.h" + +namespace leveldb { + +// Update Makefile if you change these +static const int kMajorVersion = 1; +static const int kMinorVersion = 13; + +struct Options; +struct ReadOptions; +struct WriteOptions; +class WriteBatch; + +// Abstract handle to particular state of a DB. +// A Snapshot is an immutable object and can therefore be safely +// accessed from multiple threads without any external synchronization. +class Snapshot { + protected: + virtual ~Snapshot(); +}; + +// A range of keys +struct Range { + Slice start; // Included in the range + Slice limit; // Not included in the range + + Range() { } + Range(const Slice& s, const Slice& l) : start(s), limit(l) { } +}; + +// A DB is a persistent ordered map from keys to values. +// A DB is safe for concurrent access from multiple threads without +// any external synchronization. +class DB { + public: + // Open the database with the specified "name". + // Stores a pointer to a heap-allocated database in *dbptr and returns + // OK on success. + // Stores NULL in *dbptr and returns a non-OK status on error. + // Caller should delete *dbptr when it is no longer needed. + static Status Open(const Options& options, + const std::string& name, + DB** dbptr); + + DB() { } + virtual ~DB(); + + // Set the database entry for "key" to "value". Returns OK on success, + // and a non-OK status on error. + // Note: consider setting options.sync = true. + virtual Status Put(const WriteOptions& options, + const Slice& key, + const Slice& value) = 0; + + // Remove the database entry (if any) for "key". Returns OK on + // success, and a non-OK status on error. It is not an error if "key" + // did not exist in the database. + // Note: consider setting options.sync = true. + virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; + + // Apply the specified updates to the database. + // Returns OK on success, non-OK on failure. + // Note: consider setting options.sync = true. + virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; + + // If the database contains an entry for "key" store the + // corresponding value in *value and return OK. + // + // If there is no entry for "key" leave *value unchanged and return + // a status for which Status::IsNotFound() returns true. + // + // May return some other Status on an error. + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) = 0; + + // Return a heap-allocated iterator over the contents of the database. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + // + // Caller should delete the iterator when it is no longer needed. + // The returned iterator should be deleted before this db is deleted. + virtual Iterator* NewIterator(const ReadOptions& options) = 0; + + // Return a handle to the current DB state. Iterators created with + // this handle will all observe a stable snapshot of the current DB + // state. The caller must call ReleaseSnapshot(result) when the + // snapshot is no longer needed. + virtual const Snapshot* GetSnapshot() = 0; + + // Release a previously acquired snapshot. The caller must not + // use "snapshot" after this call. + virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; + + // DB implementations can export properties about their state + // via this method. If "property" is a valid property understood by this + // DB implementation, fills "*value" with its current value and returns + // true. Otherwise returns false. + // + // + // Valid property names include: + // + // "leveldb.num-files-at-level" - return the number of files at level , + // where is an ASCII representation of a level number (e.g. "0"). + // "leveldb.stats" - returns a multi-line string that describes statistics + // 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. + virtual bool GetProperty(const Slice& property, std::string* value) = 0; + + // For each i in [0,n-1], store in "sizes[i]", the approximate + // file system space used by keys in "[range[i].start .. range[i].limit)". + // + // Note that the returned sizes measure file system space usage, so + // if the user data compresses by a factor of ten, the returned + // sizes will be one-tenth the size of the corresponding user data size. + // + // The results may not include the sizes of recently written data. + virtual void GetApproximateSizes(const Range* range, int n, + uint64_t* sizes) = 0; + + // Compact the underlying storage for the key range [*begin,*end]. + // In particular, deleted and overwritten versions are discarded, + // and the data is rearranged to reduce the cost of operations + // needed to access the data. This operation should typically only + // be invoked by users who understand the underlying implementation. + // + // begin==NULL is treated as a key before all keys in the database. + // end==NULL is treated as a key after all keys in the database. + // Therefore the following call will compact the entire database: + // db->CompactRange(NULL, NULL); + virtual void CompactRange(const Slice* begin, const Slice* end) = 0; + + private: + // No copying allowed + DB(const DB&); + void operator=(const DB&); +}; + +// Destroy the contents of the specified database. +// Be very careful using this method. +Status DestroyDB(const std::string& name, const Options& options); + +// If a DB cannot be opened, you may attempt to call this method to +// resurrect as much of the contents of the database as possible. +// Some data may be lost, so be careful when calling this function +// on a database that contains important information. +Status RepairDB(const std::string& dbname, const Options& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h new file mode 100644 index 0000000..fa32289 --- /dev/null +++ b/src/leveldb/include/leveldb/env.h @@ -0,0 +1,333 @@ +// 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. +// +// An Env is an interface used by the leveldb implementation to access +// operating system functionality like the filesystem etc. Callers +// may wish to provide a custom Env object when opening a database to +// get fine gain control; e.g., to rate limit file system operations. +// +// All Env implementations are safe for concurrent access from +// multiple threads without any external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ +#define STORAGE_LEVELDB_INCLUDE_ENV_H_ + +#include +#include +#include +#include +#include "leveldb/status.h" + +namespace leveldb { + +class FileLock; +class Logger; +class RandomAccessFile; +class SequentialFile; +class Slice; +class WritableFile; + +class Env { + public: + Env() { } + virtual ~Env(); + + // Return a default environment suitable for the current operating + // system. Sophisticated users may wish to provide their own Env + // implementation instead of relying on this default environment. + // + // The result of Default() belongs to leveldb and must never be deleted. + static Env* Default(); + + // Create a brand new sequentially-readable file with the specified name. + // On success, stores a pointer to the new file in *result and returns OK. + // On failure stores NULL in *result and returns non-OK. If the file does + // not exist, returns a non-OK status. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) = 0; + + // Create a brand new random access read-only file with the + // specified name. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. If the file does not exist, returns a non-OK + // status. + // + // The returned file may be concurrently accessed by multiple threads. + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) = 0; + + // Create an object that writes to a new file with the specified + // name. Deletes any existing file with the same name and creates a + // new file. 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. + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) = 0; + + // Returns true iff the named file exists. + virtual bool FileExists(const std::string& fname) = 0; + + // Store in *result the names of the children of the specified directory. + // The names are relative to "dir". + // Original contents of *results are dropped. + virtual Status GetChildren(const std::string& dir, + std::vector* result) = 0; + + // Delete the named file. + virtual Status DeleteFile(const std::string& fname) = 0; + + // Create the specified directory. + virtual Status CreateDir(const std::string& dirname) = 0; + + // Delete the specified directory. + virtual Status DeleteDir(const std::string& dirname) = 0; + + // Store the size of fname in *file_size. + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; + + // Rename file src to target. + virtual Status RenameFile(const std::string& src, + const std::string& target) = 0; + + // Lock the specified file. Used to prevent concurrent access to + // the same db by multiple processes. On failure, stores NULL in + // *lock and returns non-OK. + // + // On success, stores a pointer to the object that represents the + // acquired lock in *lock and returns OK. The caller should call + // UnlockFile(*lock) to release the lock. If the process exits, + // the lock will be automatically released. + // + // If somebody else already holds the lock, finishes immediately + // with a failure. I.e., this call does not wait for existing locks + // to go away. + // + // May create the named file if it does not already exist. + virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; + + // Release the lock acquired by a previous successful call to LockFile. + // REQUIRES: lock was returned by a successful LockFile() call + // REQUIRES: lock has not already been unlocked. + virtual Status UnlockFile(FileLock* lock) = 0; + + // Arrange to run "(*function)(arg)" once in a background thread. + // + // "function" may run in an unspecified thread. Multiple functions + // added to the same Env may run concurrently in different threads. + // I.e., the caller may not assume that background work items are + // serialized. + virtual void Schedule( + void (*function)(void* arg), + void* arg) = 0; + + // Start a new thread, invoking "function(arg)" within the new thread. + // When "function(arg)" returns, the thread will be destroyed. + virtual void StartThread(void (*function)(void* arg), void* arg) = 0; + + // *path is set to a temporary directory that can be used for testing. It may + // or many not have just been created. The directory may or may not differ + // between runs of the same process, but subsequent calls will return the + // same directory. + virtual Status GetTestDirectory(std::string* path) = 0; + + // Create and return a log file for storing informational messages. + virtual Status NewLogger(const std::string& fname, Logger** result) = 0; + + // Returns the number of micro-seconds since some fixed point in time. Only + // useful for computing deltas of time. + virtual uint64_t NowMicros() = 0; + + // Sleep/delay the thread for the perscribed number of micro-seconds. + virtual void SleepForMicroseconds(int micros) = 0; + + private: + // No copying allowed + Env(const Env&); + void operator=(const Env&); +}; + +// A file abstraction for reading sequentially through a file +class SequentialFile { + public: + SequentialFile() { } + virtual ~SequentialFile(); + + // Read up to "n" bytes from the file. "scratch[0..n-1]" may be + // written by this routine. Sets "*result" to the data that was + // read (including if fewer than "n" bytes were successfully read). + // May set "*result" to point at data in "scratch[0..n-1]", so + // "scratch[0..n-1]" must be live when "*result" is used. + // If an error was encountered, returns a non-OK status. + // + // REQUIRES: External synchronization + virtual Status Read(size_t n, Slice* result, char* scratch) = 0; + + // Skip "n" bytes from the file. This is guaranteed to be no + // slower that reading the same data, but may be faster. + // + // If end of file is reached, skipping will stop at the end of the + // file, and Skip will return OK. + // + // REQUIRES: External synchronization + virtual Status Skip(uint64_t n) = 0; + + private: + // No copying allowed + SequentialFile(const SequentialFile&); + void operator=(const SequentialFile&); +}; + +// A file abstraction for randomly reading the contents of a file. +class RandomAccessFile { + public: + RandomAccessFile() { } + virtual ~RandomAccessFile(); + + // Read up to "n" bytes from the file starting at "offset". + // "scratch[0..n-1]" may be written by this routine. Sets "*result" + // to the data that was read (including if fewer than "n" bytes were + // successfully read). May set "*result" to point at data in + // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when + // "*result" is used. If an error was encountered, returns a non-OK + // status. + // + // Safe for concurrent use by multiple threads. + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const = 0; + + private: + // No copying allowed + RandomAccessFile(const RandomAccessFile&); + void operator=(const RandomAccessFile&); +}; + +// A file abstraction for sequential writing. The implementation +// must provide buffering since callers may append small fragments +// at a time to the file. +class WritableFile { + public: + WritableFile() { } + virtual ~WritableFile(); + + virtual Status Append(const Slice& data) = 0; + virtual Status Close() = 0; + virtual Status Flush() = 0; + virtual Status Sync() = 0; + + private: + // No copying allowed + WritableFile(const WritableFile&); + void operator=(const WritableFile&); +}; + +// An interface for writing log messages. +class Logger { + public: + Logger() { } + virtual ~Logger(); + + // Write an entry to the log file with the specified format. + virtual void Logv(const char* format, va_list ap) = 0; + + private: + // No copying allowed + Logger(const Logger&); + void operator=(const Logger&); +}; + + +// Identifies a locked file. +class FileLock { + public: + FileLock() { } + virtual ~FileLock(); + private: + // No copying allowed + FileLock(const FileLock&); + void operator=(const FileLock&); +}; + +// Log the specified data to *info_log if info_log is non-NULL. +extern void Log(Logger* info_log, const char* format, ...) +# if defined(__GNUC__) || defined(__clang__) + __attribute__((__format__ (__printf__, 2, 3))) +# endif + ; + +// A utility routine: write "data" to the named file. +extern Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname); + +// A utility routine: read contents of named file into *data +extern Status ReadFileToString(Env* env, const std::string& fname, + std::string* data); + +// An implementation of Env that forwards all calls to another Env. +// May be useful to clients who wish to override just part of the +// functionality of another Env. +class EnvWrapper : public Env { + public: + // Initialize an EnvWrapper that delegates all calls to *t + explicit EnvWrapper(Env* t) : target_(t) { } + virtual ~EnvWrapper(); + + // Return the target to which this Env forwards all calls + Env* target() const { return target_; } + + // The following text is boilerplate that forwards all methods to target() + Status NewSequentialFile(const std::string& f, SequentialFile** r) { + return target_->NewSequentialFile(f, r); + } + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + return target_->NewRandomAccessFile(f, r); + } + Status NewWritableFile(const std::string& f, WritableFile** r) { + return target_->NewWritableFile(f, r); + } + bool FileExists(const std::string& f) { return target_->FileExists(f); } + Status GetChildren(const std::string& dir, std::vector* r) { + return target_->GetChildren(dir, r); + } + Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); } + Status CreateDir(const std::string& d) { return target_->CreateDir(d); } + Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); } + Status GetFileSize(const std::string& f, uint64_t* s) { + return target_->GetFileSize(f, s); + } + Status RenameFile(const std::string& s, const std::string& t) { + return target_->RenameFile(s, t); + } + Status LockFile(const std::string& f, FileLock** l) { + return target_->LockFile(f, l); + } + Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); } + void Schedule(void (*f)(void*), void* a) { + return target_->Schedule(f, a); + } + void StartThread(void (*f)(void*), void* a) { + return target_->StartThread(f, a); + } + virtual Status GetTestDirectory(std::string* path) { + return target_->GetTestDirectory(path); + } + virtual Status NewLogger(const std::string& fname, Logger** result) { + return target_->NewLogger(fname, result); + } + uint64_t NowMicros() { + return target_->NowMicros(); + } + void SleepForMicroseconds(int micros) { + target_->SleepForMicroseconds(micros); + } + private: + Env* target_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/src/leveldb/include/leveldb/filter_policy.h b/src/leveldb/include/leveldb/filter_policy.h new file mode 100644 index 0000000..1fba080 --- /dev/null +++ b/src/leveldb/include/leveldb/filter_policy.h @@ -0,0 +1,70 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A database can be configured with a custom FilterPolicy object. +// This object is responsible for creating a small filter from a set +// of keys. These filters are stored in leveldb and are consulted +// automatically by leveldb to decide whether or not to read some +// information from disk. In many cases, a filter can cut down the +// number of disk seeks form a handful to a single disk seek per +// DB::Get() call. +// +// Most people will want to use the builtin bloom filter support (see +// NewBloomFilterPolicy() below). + +#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ +#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ + +#include + +namespace leveldb { + +class Slice; + +class FilterPolicy { + public: + virtual ~FilterPolicy(); + + // Return the name of this policy. Note that if the filter encoding + // changes in an incompatible way, the name returned by this method + // must be changed. Otherwise, old incompatible filters may be + // passed to methods of this type. + virtual const char* Name() const = 0; + + // keys[0,n-1] contains a list of keys (potentially with duplicates) + // that are ordered according to the user supplied comparator. + // Append a filter that summarizes keys[0,n-1] to *dst. + // + // Warning: do not change the initial contents of *dst. Instead, + // append the newly constructed filter to *dst. + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) + const = 0; + + // "filter" contains the data appended by a preceding call to + // CreateFilter() on this class. This method must return true if + // the key was in the list of keys passed to CreateFilter(). + // This method may return true or false if the key was not on the + // list, but it should aim to return false with a high probability. + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; +}; + +// Return a new filter policy that uses a bloom filter with approximately +// the specified number of bits per key. A good value for bits_per_key +// is 10, which yields a filter with ~ 1% false positive rate. +// +// Callers must delete the result after any database that is using the +// result has been closed. +// +// Note: if you are using a custom comparator that ignores some parts +// of the keys being compared, you must not use NewBloomFilterPolicy() +// and must provide your own FilterPolicy that also ignores the +// corresponding parts of the keys. For example, if the comparator +// ignores trailing spaces, it would be incorrect to use a +// FilterPolicy (like NewBloomFilterPolicy) that does not ignore +// trailing spaces in keys. +extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); + +} + +#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/src/leveldb/include/leveldb/iterator.h b/src/leveldb/include/leveldb/iterator.h new file mode 100644 index 0000000..ad543eb --- /dev/null +++ b/src/leveldb/include/leveldb/iterator.h @@ -0,0 +1,100 @@ +// 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. +// +// An iterator yields a sequence of key/value pairs from a source. +// The following class defines the interface. Multiple implementations +// are provided by this library. In particular, iterators are provided +// to access the contents of a Table or a DB. +// +// Multiple threads can invoke const methods on an Iterator without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Iterator must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ + +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class Iterator { + public: + Iterator(); + virtual ~Iterator(); + + // An iterator is either positioned at a key/value pair, or + // not valid. This method returns true iff the iterator is valid. + virtual bool Valid() const = 0; + + // Position at the first key in the source. The iterator is Valid() + // after this call iff the source is not empty. + virtual void SeekToFirst() = 0; + + // Position at the last key in the source. The iterator is + // 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 + // 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; + + // Moves to the next entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the last entry in the source. + // REQUIRES: Valid() + virtual void Next() = 0; + + // Moves to the previous entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the first entry in source. + // REQUIRES: Valid() + virtual void Prev() = 0; + + // Return the key for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice key() const = 0; + + // Return the value for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: !AtEnd() && !AtStart() + virtual Slice value() const = 0; + + // If an error has occurred, return it. Else return an ok status. + virtual Status status() const = 0; + + // Clients are allowed to register function/arg1/arg2 triples that + // will be invoked when this iterator is destroyed. + // + // Note that unlike all of the preceding methods, this method is + // not abstract and therefore clients should not override it. + typedef void (*CleanupFunction)(void* arg1, void* arg2); + void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); + + private: + struct Cleanup { + CleanupFunction function; + void* arg1; + void* arg2; + Cleanup* next; + }; + Cleanup cleanup_; + + // No copying allowed + Iterator(const Iterator&); + void operator=(const Iterator&); +}; + +// Return an empty iterator (yields nothing). +extern Iterator* NewEmptyIterator(); + +// Return an empty iterator with the specified status. +extern Iterator* NewErrorIterator(const Status& status); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h new file mode 100644 index 0000000..fdda718 --- /dev/null +++ b/src/leveldb/include/leveldb/options.h @@ -0,0 +1,195 @@ +// 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_INCLUDE_OPTIONS_H_ +#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ + +#include + +namespace leveldb { + +class Cache; +class Comparator; +class Env; +class FilterPolicy; +class Logger; +class Snapshot; + +// DB contents are stored in a set of blocks, each of which holds a +// sequence of key,value pairs. Each block may be compressed before +// being stored in a file. The following enum describes which +// compression method (if any) is used to compress a block. +enum CompressionType { + // NOTE: do not change the values of existing entries, as these are + // part of the persistent format on disk. + kNoCompression = 0x0, + kSnappyCompression = 0x1 +}; + +// Options to control the behavior of a database (passed to DB::Open) +struct Options { + // ------------------- + // Parameters that affect behavior + + // Comparator used to define the order of keys in the table. + // Default: a comparator that uses lexicographic byte-wise ordering + // + // REQUIRES: The client must ensure that the comparator supplied + // here has the same name and orders keys *exactly* the same as the + // comparator provided to previous open calls on the same DB. + const Comparator* comparator; + + // If true, the database will be created if it is missing. + // Default: false + bool create_if_missing; + + // If true, an error is raised if the database already exists. + // Default: false + bool error_if_exists; + + // If true, the implementation will do aggressive checking of the + // data it is processing and will stop early if it detects any + // errors. This may have unforeseen ramifications: for example, a + // corruption of one DB entry may cause a large number of entries to + // become unreadable or for the entire DB to become unopenable. + // Default: false + bool paranoid_checks; + + // Use the specified object to interact with the environment, + // e.g. to read/write files, schedule background work, etc. + // Default: Env::Default() + Env* env; + + // Any internal progress/error information generated by the db will + // be written to info_log if it is non-NULL, or to a file stored + // in the same directory as the DB contents if info_log is NULL. + // Default: NULL + Logger* info_log; + + // ------------------- + // Parameters that affect performance + + // Amount of data to build up in memory (backed by an unsorted log + // on disk) before converting to a sorted on-disk file. + // + // Larger values increase performance, especially during bulk loads. + // Up to two write buffers may be held in memory at the same time, + // so you may wish to adjust this parameter to control memory usage. + // Also, a larger write buffer will result in a longer recovery time + // the next time the database is opened. + // + // Default: 4MB + size_t write_buffer_size; + + // Number of open files that can be used by the DB. You may need to + // increase this if your database has a large working set (budget + // one open file per 2MB of working set). + // + // Default: 1000 + int max_open_files; + + // Control over blocks (user data is stored in a set of blocks, and + // a block is the unit of reading from disk). + + // If non-NULL, use the specified cache for blocks. + // If NULL, leveldb will automatically create and use an 8MB internal cache. + // Default: NULL + Cache* block_cache; + + // Approximate size of user data packed per block. Note that the + // block size specified here corresponds to uncompressed data. The + // actual size of the unit read from disk may be smaller if + // compression is enabled. This parameter can be changed dynamically. + // + // Default: 4K + size_t block_size; + + // Number of keys between restart points for delta encoding of keys. + // This parameter can be changed dynamically. Most clients should + // leave this parameter alone. + // + // Default: 16 + int block_restart_interval; + + // Compress blocks using the specified compression algorithm. This + // parameter can be changed dynamically. + // + // Default: kSnappyCompression, which gives lightweight but fast + // compression. + // + // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: + // ~200-500MB/s compression + // ~400-800MB/s decompression + // Note that these speeds are significantly faster than most + // persistent storage speeds, and therefore it is typically never + // worth switching to kNoCompression. Even if the input data is + // incompressible, the kSnappyCompression implementation will + // efficiently detect that and will switch to uncompressed mode. + CompressionType compression; + + // If non-NULL, use the specified filter policy to reduce disk reads. + // Many applications will benefit from passing the result of + // NewBloomFilterPolicy() here. + // + // Default: NULL + const FilterPolicy* filter_policy; + + // Create an Options object with default values for all fields. + Options(); +}; + +// Options that control read operations +struct ReadOptions { + // If true, all data read from underlying storage will be + // verified against corresponding checksums. + // Default: false + bool verify_checksums; + + // Should the data read for this iteration be cached in memory? + // Callers may wish to set this field to false for bulk scans. + // Default: true + bool fill_cache; + + // If "snapshot" is non-NULL, read as of the supplied snapshot + // (which must belong to the DB that is being read and which must + // not have been released). If "snapshot" is NULL, use an impliicit + // snapshot of the state at the beginning of this read operation. + // Default: NULL + const Snapshot* snapshot; + + ReadOptions() + : verify_checksums(false), + fill_cache(true), + snapshot(NULL) { + } +}; + +// Options that control write operations +struct WriteOptions { + // If true, the write will be flushed from the operating system + // buffer cache (by calling WritableFile::Sync()) before the write + // is considered complete. If this flag is true, writes will be + // slower. + // + // If this flag is false, and the machine crashes, some recent + // writes may be lost. Note that if it is just the process that + // crashes (i.e., the machine does not reboot), no writes will be + // lost even if sync==false. + // + // In other words, a DB write with sync==false has similar + // crash semantics as the "write()" system call. A DB write + // with sync==true has similar crash semantics to a "write()" + // system call followed by "fsync()". + // + // Default: false + bool sync; + + WriteOptions() + : sync(false) { + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/src/leveldb/include/leveldb/slice.h b/src/leveldb/include/leveldb/slice.h new file mode 100644 index 0000000..74ea8fa --- /dev/null +++ b/src/leveldb/include/leveldb/slice.h @@ -0,0 +1,109 @@ +// 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. +// +// Slice is a simple structure containing a pointer into some external +// storage and a size. The user of a Slice must ensure that the slice +// is not used after the corresponding external storage has been +// deallocated. +// +// Multiple threads can invoke const methods on a Slice without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Slice must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ +#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Slice { + public: + // Create an empty slice. + Slice() : data_(""), size_(0) { } + + // Create a slice that refers to d[0,n-1]. + Slice(const char* d, size_t n) : data_(d), size_(n) { } + + // Create a slice that refers to the contents of "s" + Slice(const std::string& s) : data_(s.data()), size_(s.size()) { } + + // Create a slice that refers to s[0,strlen(s)-1] + Slice(const char* s) : data_(s), size_(strlen(s)) { } + + // Return a pointer to the beginning of the referenced data + const char* data() const { return data_; } + + // Return the length (in bytes) of the referenced data + size_t size() const { return size_; } + + // Return true iff the length of the referenced data is zero + bool empty() const { return size_ == 0; } + + // Return the ith byte in the referenced data. + // REQUIRES: n < size() + char operator[](size_t n) const { + assert(n < size()); + return data_[n]; + } + + // Change this slice to refer to an empty array + void clear() { data_ = ""; size_ = 0; } + + // Drop the first "n" bytes from this slice. + void remove_prefix(size_t n) { + assert(n <= size()); + data_ += n; + size_ -= n; + } + + // Return a string that contains the copy of the referenced data. + std::string ToString() const { return std::string(data_, size_); } + + // Three-way comparison. Returns value: + // < 0 iff "*this" < "b", + // == 0 iff "*this" == "b", + // > 0 iff "*this" > "b" + int compare(const Slice& b) const; + + // Return true iff "x" is a prefix of "*this" + bool starts_with(const Slice& x) const { + return ((size_ >= x.size_) && + (memcmp(data_, x.data_, x.size_) == 0)); + } + + private: + const char* data_; + size_t size_; + + // Intentionally copyable +}; + +inline bool operator==(const Slice& x, const Slice& y) { + return ((x.size() == y.size()) && + (memcmp(x.data(), y.data(), x.size()) == 0)); +} + +inline bool operator!=(const Slice& x, const Slice& y) { + return !(x == y); +} + +inline int Slice::compare(const Slice& b) const { + const int min_len = (size_ < b.size_) ? size_ : b.size_; + int r = memcmp(data_, b.data_, min_len); + if (r == 0) { + if (size_ < b.size_) r = -1; + else if (size_ > b.size_) r = +1; + } + return r; +} + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/src/leveldb/include/leveldb/status.h b/src/leveldb/include/leveldb/status.h new file mode 100644 index 0000000..11dbd4b --- /dev/null +++ b/src/leveldb/include/leveldb/status.h @@ -0,0 +1,106 @@ +// 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. +// +// A Status encapsulates the result of an operation. It may indicate success, +// or it may indicate an error with an associated error message. +// +// Multiple threads can invoke const methods on a Status without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Status must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ +#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Status { + public: + // Create a success status. + Status() : state_(NULL) { } + ~Status() { delete[] state_; } + + // Copy the specified status. + Status(const Status& s); + void operator=(const Status& s); + + // Return a success status. + static Status OK() { return Status(); } + + // Return error status of an appropriate type. + static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotFound, msg, msg2); + } + static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kCorruption, msg, msg2); + } + static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotSupported, msg, msg2); + } + static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kInvalidArgument, msg, msg2); + } + static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kIOError, msg, msg2); + } + + // Returns true iff the status indicates success. + bool ok() const { return (state_ == NULL); } + + // Returns true iff the status indicates a NotFound error. + bool IsNotFound() const { return code() == kNotFound; } + + // Returns true iff the status indicates a Corruption error. + bool IsCorruption() const { return code() == kCorruption; } + + // Returns true iff the status indicates an IOError. + bool IsIOError() const { return code() == kIOError; } + + // Return a string representation of this status suitable for printing. + // Returns the string "OK" for success. + std::string ToString() const; + + private: + // OK status has a NULL state_. Otherwise, state_ is a new[] array + // of the following form: + // state_[0..3] == length of message + // state_[4] == code + // state_[5..] == message + const char* state_; + + enum Code { + kOk = 0, + kNotFound = 1, + kCorruption = 2, + kNotSupported = 3, + kInvalidArgument = 4, + kIOError = 5 + }; + + Code code() const { + return (state_ == NULL) ? kOk : static_cast(state_[4]); + } + + Status(Code code, const Slice& msg, const Slice& msg2); + static const char* CopyState(const char* s); +}; + +inline Status::Status(const Status& s) { + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); +} +inline void Status::operator=(const Status& s) { + // The following condition catches both aliasing (when this == &s), + // and the common case where both s and *this are ok. + if (state_ != s.state_) { + delete[] state_; + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/src/leveldb/include/leveldb/table.h b/src/leveldb/include/leveldb/table.h new file mode 100644 index 0000000..a9746c3 --- /dev/null +++ b/src/leveldb/include/leveldb/table.h @@ -0,0 +1,85 @@ +// 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_INCLUDE_TABLE_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ + +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +class Block; +class BlockHandle; +class Footer; +struct Options; +class RandomAccessFile; +struct ReadOptions; +class TableCache; + +// A Table is a sorted map from strings to strings. Tables are +// immutable and persistent. A Table may be safely accessed from +// multiple threads without external synchronization. +class Table { + public: + // Attempt to open the table that is stored in bytes [0..file_size) + // of "file", and read the metadata entries necessary to allow + // retrieving data from the table. + // + // If successful, returns ok and sets "*table" to the newly opened + // table. The client should delete "*table" when no longer needed. + // If there was an error while initializing the table, sets "*table" + // to NULL and returns a non-ok status. Does not take ownership of + // "*source", but the client must ensure that "source" remains live + // for the duration of the returned table's lifetime. + // + // *file must remain live while this Table is in use. + static Status Open(const Options& options, + RandomAccessFile* file, + uint64_t file_size, + Table** table); + + ~Table(); + + // Returns a new iterator over the table contents. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + Iterator* NewIterator(const ReadOptions&) const; + + // Given a key, return an approximate byte offset in the file where + // the data for that key begins (or would begin if the key were + // present in the file). The returned value is in terms of file + // bytes, and so includes effects like compression of the underlying data. + // E.g., the approximate offset of the last key in the table will + // be close to the file length. + uint64_t ApproximateOffsetOf(const Slice& key) const; + + private: + struct Rep; + Rep* rep_; + + explicit Table(Rep* rep) { rep_ = rep; } + static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); + + // Calls (*handle_result)(arg, ...) with the entry found after a call + // to Seek(key). May not make such a call if filter policy says + // that key is not present. + friend class TableCache; + Status InternalGet( + const ReadOptions&, const Slice& key, + void* arg, + void (*handle_result)(void* arg, const Slice& k, const Slice& v)); + + + void ReadMeta(const Footer& footer); + void ReadFilter(const Slice& filter_handle_value); + + // No copying allowed + Table(const Table&); + void operator=(const Table&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/src/leveldb/include/leveldb/table_builder.h b/src/leveldb/include/leveldb/table_builder.h new file mode 100644 index 0000000..5fd1dc7 --- /dev/null +++ b/src/leveldb/include/leveldb/table_builder.h @@ -0,0 +1,92 @@ +// 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. +// +// TableBuilder provides the interface used to build a Table +// (an immutable and sorted map from keys to values). +// +// Multiple threads can invoke const methods on a TableBuilder without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same TableBuilder must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ + +#include +#include "leveldb/options.h" +#include "leveldb/status.h" + +namespace leveldb { + +class BlockBuilder; +class BlockHandle; +class WritableFile; + +class TableBuilder { + public: + // Create a builder that will store the contents of the table it is + // building in *file. Does not close the file. It is up to the + // caller to close the file after calling Finish(). + TableBuilder(const Options& options, WritableFile* file); + + // REQUIRES: Either Finish() or Abandon() has been called. + ~TableBuilder(); + + // Change the options used by this builder. Note: only some of the + // option fields can be changed after construction. If a field is + // not allowed to change dynamically and its value in the structure + // passed to the constructor is different from its value in the + // structure passed to this method, this method will return an error + // without changing any fields. + Status ChangeOptions(const Options& options); + + // Add key,value to the table being constructed. + // REQUIRES: key is after any previously added key according to comparator. + // REQUIRES: Finish(), Abandon() have not been called + void Add(const Slice& key, const Slice& value); + + // Advanced operation: flush any buffered key/value pairs to file. + // Can be used to ensure that two adjacent entries never live in + // the same data block. Most clients should not need to use this method. + // REQUIRES: Finish(), Abandon() have not been called + void Flush(); + + // Return non-ok iff some error has been detected. + Status status() const; + + // Finish building the table. Stops using the file passed to the + // constructor after this function returns. + // REQUIRES: Finish(), Abandon() have not been called + Status Finish(); + + // Indicate that the contents of this builder should be abandoned. Stops + // using the file passed to the constructor after this function returns. + // If the caller is not going to call Finish(), it must call Abandon() + // before destroying this builder. + // REQUIRES: Finish(), Abandon() have not been called + void Abandon(); + + // Number of calls to Add() so far. + uint64_t NumEntries() const; + + // Size of the file generated so far. If invoked after a successful + // Finish() call, returns the size of the final generated file. + uint64_t FileSize() const; + + private: + bool ok() const { return status().ok(); } + void WriteBlock(BlockBuilder* block, BlockHandle* handle); + void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); + + struct Rep; + Rep* rep_; + + // No copying allowed + TableBuilder(const TableBuilder&); + void operator=(const TableBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/src/leveldb/include/leveldb/write_batch.h b/src/leveldb/include/leveldb/write_batch.h new file mode 100644 index 0000000..ee9aab6 --- /dev/null +++ b/src/leveldb/include/leveldb/write_batch.h @@ -0,0 +1,64 @@ +// 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. +// +// WriteBatch holds a collection of updates to apply atomically to a DB. +// +// The updates are applied in the order in which they are added +// to the WriteBatch. For example, the value of "key" will be "v3" +// after the following batch is written: +// +// batch.Put("key", "v1"); +// batch.Delete("key"); +// batch.Put("key", "v2"); +// batch.Put("key", "v3"); +// +// Multiple threads can invoke const methods on a WriteBatch without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same WriteBatch must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ +#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ + +#include +#include "leveldb/status.h" + +namespace leveldb { + +class Slice; + +class WriteBatch { + public: + WriteBatch(); + ~WriteBatch(); + + // Store the mapping "key->value" in the database. + void Put(const Slice& key, const Slice& value); + + // If the database contains a mapping for "key", erase it. Else do nothing. + void Delete(const Slice& key); + + // Clear all updates buffered in this batch. + void Clear(); + + // Support for iterating over the contents of a batch. + class Handler { + public: + virtual ~Handler(); + virtual void Put(const Slice& key, const Slice& value) = 0; + virtual void Delete(const Slice& key) = 0; + }; + Status Iterate(Handler* handler) const; + + private: + friend class WriteBatchInternal; + + std::string rep_; // See comment in write_batch.cc for the format of rep_ + + // Intentionally copyable +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/src/leveldb/issues/issue178_test.cc b/src/leveldb/issues/issue178_test.cc new file mode 100644 index 0000000..1b1cf8b --- /dev/null +++ b/src/leveldb/issues/issue178_test.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2013 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. + +// Test for issue 178: a manual compaction causes deleted data to reappear. +#include +#include +#include + +#include "leveldb/db.h" +#include "leveldb/write_batch.h" +#include "util/testharness.h" + +namespace { + +const int kNumKeys = 1100000; + +std::string Key1(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "my_key_%d", i); + return buf; +} + +std::string Key2(int i) { + return Key1(i) + "_xxx"; +} + +class Issue178 { }; + +TEST(Issue178, Test) { + // Get rid of any state from an old run. + std::string dbpath = leveldb::test::TmpDir() + "/leveldb_cbug_test"; + DestroyDB(dbpath, leveldb::Options()); + + // Open database. Disable compression since it affects the creation + // of layers and the code below is trying to test against a very + // specific scenario. + leveldb::DB* db; + leveldb::Options db_options; + db_options.create_if_missing = true; + db_options.compression = leveldb::kNoCompression; + ASSERT_OK(leveldb::DB::Open(db_options, dbpath, &db)); + + // create first key range + leveldb::WriteBatch batch; + for (size_t i = 0; i < kNumKeys; i++) { + batch.Put(Key1(i), "value for range 1 key"); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // create second key range + batch.Clear(); + for (size_t i = 0; i < kNumKeys; i++) { + batch.Put(Key2(i), "value for range 2 key"); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // delete second key range + batch.Clear(); + for (size_t i = 0; i < kNumKeys; i++) { + batch.Delete(Key2(i)); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // compact database + std::string start_key = Key1(0); + std::string end_key = Key1(kNumKeys - 1); + leveldb::Slice least(start_key.data(), start_key.size()); + leveldb::Slice greatest(end_key.data(), end_key.size()); + + // commenting out the line below causes the example to work correctly + db->CompactRange(&least, &greatest); + + // count the keys + leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions()); + size_t num_keys = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + num_keys++; + } + delete iter; + ASSERT_EQ(kNumKeys, num_keys) << "Bad number of keys"; + + // close database + delete db; + DestroyDB(dbpath, leveldb::Options()); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/port/README b/src/leveldb/port/README new file mode 100644 index 0000000..422563e --- /dev/null +++ b/src/leveldb/port/README @@ -0,0 +1,10 @@ +This directory contains interfaces and implementations that isolate the +rest of the package from platform details. + +Code in the rest of the package includes "port.h" from this directory. +"port.h" in turn includes a platform specific "port_.h" file +that provides the platform specific implementation. + +See port_posix.h for an example of what must be provided in a platform +specific header file. + diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h new file mode 100644 index 0000000..844fba2 --- /dev/null +++ b/src/leveldb/port/atomic_pointer.h @@ -0,0 +1,224 @@ +// 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. + +// AtomicPointer provides storage for a lock-free pointer. +// Platform-dependent implementation of AtomicPointer: +// - If the platform provides a cheap barrier, we use it with raw pointers +// - If cstdatomic is present (on newer versions of gcc, it is), we use +// a cstdatomic-based AtomicPointer. However we prefer the memory +// barrier based version, because at least on a gcc 4.4 32-bit build +// on linux, we have encountered a buggy +// implementation. Also, some implementations are much +// slower than a memory-barrier based implementation (~16ns for +// based acquire-load vs. ~1ns for a barrier based +// acquire-load). +// This code is based on atomicops-internals-* in Google's perftools: +// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase + +#ifndef PORT_ATOMIC_POINTER_H_ +#define PORT_ATOMIC_POINTER_H_ + +#include +#ifdef LEVELDB_CSTDATOMIC_PRESENT +#include +#endif +#ifdef OS_WIN +#include +#endif +#ifdef OS_MACOSX +#include +#endif + +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) +#define ARCH_CPU_PPC_FAMILY 1 +#endif + +namespace leveldb { +namespace port { + +// Define MemoryBarrier() if available +// Windows on x86 +#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) +// windows.h already provides a MemoryBarrier(void) macro +// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Mac OS +#elif defined(OS_MACOSX) +inline void MemoryBarrier() { + OSMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Gcc on x86 +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + __asm__ __volatile__("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Sun Studio +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + asm volatile("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// ARM Linux +#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +// The Linux ARM kernel provides a highly optimized device-specific memory +// barrier function at a fixed memory address that is mapped in every +// user-level process. +// +// This beats using CPU-specific instructions which are, on single-core +// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more +// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking +// shows that the extra function call cost is completely negligible on +// multi-core devices. +// +inline void MemoryBarrier() { + (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// PPC +#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // TODO for some powerpc expert: is there a cheaper suitable variant? + // Perhaps by having separate barriers for acquire and release ops. + asm volatile("sync" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +#endif + +// AtomicPointer built using platform-specific MemoryBarrier() +#if defined(LEVELDB_HAVE_MEMORY_BARRIER) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* p) : rep_(p) {} + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } + inline void* Acquire_Load() const { + void* result = rep_; + MemoryBarrier(); + return result; + } + inline void Release_Store(void* v) { + MemoryBarrier(); + rep_ = v; + } +}; + +// AtomicPointer based on +#elif defined(LEVELDB_CSTDATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +// Atomic pointer based on sparc memory barriers +#elif defined(__sparcv9) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val; + __asm__ __volatile__ ( + "ldx [%[rep_]], %[val] \n\t" + "membar #LoadLoad|#LoadStore \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory"); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "membar #LoadStore|#StoreStore \n\t" + "stx %[v], [%[rep_]] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory"); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// Atomic pointer based on ia64 acq/rel +#elif defined(__ia64) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val ; + __asm__ __volatile__ ( + "ld8.acq %[val] = [%[rep_]] \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory" + ); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "st8.rel [%[rep_]] = %[v] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory" + ); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// We have neither MemoryBarrier(), nor +#else +#error Please implement AtomicPointer for this platform. + +#endif + +#undef LEVELDB_HAVE_MEMORY_BARRIER +#undef ARCH_CPU_X86_FAMILY +#undef ARCH_CPU_ARM_FAMILY +#undef ARCH_CPU_PPC_FAMILY + +} // namespace port +} // namespace leveldb + +#endif // PORT_ATOMIC_POINTER_H_ diff --git a/src/leveldb/port/port.h b/src/leveldb/port/port.h new file mode 100644 index 0000000..4baafa8 --- /dev/null +++ b/src/leveldb/port/port.h @@ -0,0 +1,21 @@ +// 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_PORT_PORT_H_ +#define STORAGE_LEVELDB_PORT_PORT_H_ + +#include + +// Include the appropriate platform specific file below. If you are +// porting to a new platform, see "port_example.h" for documentation +// of what the new port_.h file must provide. +#if defined(LEVELDB_PLATFORM_POSIX) +# include "port/port_posix.h" +#elif defined(LEVELDB_PLATFORM_CHROMIUM) +# include "port/port_chromium.h" +#elif defined(LEVELDB_PLATFORM_WINDOWS) +# include "port/port_win.h" +#endif + +#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h new file mode 100644 index 0000000..ab9e489 --- /dev/null +++ b/src/leveldb/port/port_example.h @@ -0,0 +1,135 @@ +// 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. +// +// This file contains the specification, but not the implementations, +// of the types/operations/etc. that should be defined by a platform +// specific port_.h file. Use this file as a reference for +// how to port this package to a new platform. + +#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ +#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ + +namespace leveldb { +namespace port { + +// TODO(jorlow): Many of these belong more in the environment class rather than +// here. We should try moving them and see if it affects perf. + +// The following boolean constant must be true on a little-endian machine +// and false otherwise. +static const bool kLittleEndian = true /* or some other expression */; + +// ------------------ Threading ------------------- + +// A Mutex represents an exclusive lock. +class Mutex { + public: + Mutex(); + ~Mutex(); + + // Lock the mutex. Waits until other lockers have exited. + // Will deadlock if the mutex is already locked by this thread. + void Lock(); + + // Unlock the mutex. + // REQUIRES: This mutex was locked by this thread. + void Unlock(); + + // Optionally crash if this thread does not hold this mutex. + // The implementation must be fast, especially if NDEBUG is + // defined. The implementation is allowed to skip all checks. + void AssertHeld(); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + + // Atomically release *mu and block on this condition variable until + // either a call to SignalAll(), or a call to Signal() that picks + // this thread to wakeup. + // REQUIRES: this thread holds *mu + void Wait(); + + // If there are some threads waiting, wake up at least one of them. + void Signal(); + + // Wake up all waiting threads. + void SignallAll(); +}; + +// Thread-safe initialization. +// Used as follows: +// static port::OnceType init_control = LEVELDB_ONCE_INIT; +// static void Initializer() { ... do something ...; } +// ... +// port::InitOnce(&init_control, &Initializer); +typedef intptr_t OnceType; +#define LEVELDB_ONCE_INIT 0 +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// A type that holds a pointer that can be read or written atomically +// (i.e., without word-tearing.) +class AtomicPointer { + private: + intptr_t rep_; + public: + // Initialize to arbitrary value + AtomicPointer(); + + // Initialize to hold v + explicit AtomicPointer(void* v) : rep_(v) { } + + // Read and return the stored pointer with the guarantee that no + // later memory access (read or write) by this thread can be + // reordered ahead of this read. + void* Acquire_Load() const; + + // Set v as the stored pointer with the guarantee that no earlier + // memory access (read or write) by this thread can be reordered + // after this store. + void Release_Store(void* v); + + // Read the stored pointer with no ordering guarantees. + void* NoBarrier_Load() const; + + // Set va as the stored pointer with no ordering guarantees. + void NoBarrier_Store(void* v); +}; + +// ------------------ Compression ------------------- + +// Store the snappy compression of "input[0,input_length-1]" in *output. +// Returns false if snappy is not supported by this port. +extern bool Snappy_Compress(const char* input, size_t input_length, + std::string* output); + +// If input[0,input_length-1] looks like a valid snappy compressed +// buffer, store the size of the uncompressed data in *result and +// return true. Else return false. +extern bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result); + +// Attempt to snappy uncompress input[0,input_length-1] into *output. +// Returns true if successful, false if the input is invalid lightweight +// compressed data. +// +// REQUIRES: at least the first "n" bytes of output[] must be writable +// where "n" is the result of a successful call to +// Snappy_GetUncompressedLength. +extern bool Snappy_Uncompress(const char* input_data, size_t input_length, + char* output); + +// ------------------ Miscellaneous ------------------- + +// If heap profiling is not supported, returns false. +// Else repeatedly calls (*func)(arg, data, n) and then returns true. +// The concatenation of all "data[0,n-1]" fragments is the heap profile. +extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc new file mode 100644 index 0000000..5ba127a --- /dev/null +++ b/src/leveldb/port/port_posix.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "port/port_posix.h" + +#include +#include +#include +#include "util/logging.h" + +namespace leveldb { +namespace port { + +static void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } +} + +Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); } + +Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } + +void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } + +void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } + +CondVar::CondVar(Mutex* mu) + : mu_(mu) { + PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); +} + +CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } + +void CondVar::Wait() { + PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); +} + +void CondVar::Signal() { + PthreadCall("signal", pthread_cond_signal(&cv_)); +} + +void CondVar::SignalAll() { + PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + PthreadCall("once", pthread_once(once, initializer)); +} + +} // namespace port +} // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h new file mode 100644 index 0000000..21c845e --- /dev/null +++ b/src/leveldb/port/port_posix.h @@ -0,0 +1,161 @@ +// 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. +// +// See port_example.h for documentation for the following types/functions. + +#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ +#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ + +#undef PLATFORM_IS_LITTLE_ENDIAN +#if defined(OS_MACOSX) + #include + #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER) + #define PLATFORM_IS_LITTLE_ENDIAN \ + (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN) + #endif +#elif defined(OS_SOLARIS) + #include + #ifdef _LITTLE_ENDIAN + #define PLATFORM_IS_LITTLE_ENDIAN true + #else + #define PLATFORM_IS_LITTLE_ENDIAN false + #endif +#elif defined(OS_FREEBSD) + #include + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\ + defined(OS_DRAGONFLYBSD) + #include + #include +#elif defined(OS_HPUX) + #define PLATFORM_IS_LITTLE_ENDIAN false +#elif defined(OS_ANDROID) + // Due to a bug in the NDK x86 definition, + // _BYTE_ORDER must be used instead of __BYTE_ORDER on Android. + // See http://code.google.com/p/android/issues/detail?id=39824 + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#else + #include +#endif + +#include +#ifdef SNAPPY +#include +#endif +#include +#include +#include "port/atomic_pointer.h" + +#ifndef PLATFORM_IS_LITTLE_ENDIAN +#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) +#endif + +#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ + defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ + defined(OS_ANDROID) || defined(OS_HPUX) +// Use fread/fwrite/fflush on platforms without _unlocked variants +#define fread_unlocked fread +#define fwrite_unlocked fwrite +#define fflush_unlocked fflush +#endif + +#if defined(OS_FREEBSD) ||\ + defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) +// Use fsync() on platforms without fdatasync() +#define fdatasync fsync +#endif + +#if defined(OS_MACOSX) +#define fdatasync(fd) fcntl(fd, F_FULLFSYNC, 0) +#endif + +#if defined(OS_ANDROID) && __ANDROID_API__ < 9 +// fdatasync() was only introduced in API level 9 on Android. Use fsync() +// when targetting older platforms. +#define fdatasync fsync +#endif + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN; +#undef PLATFORM_IS_LITTLE_ENDIAN + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld() { } + + private: + friend class CondVar; + pthread_mutex_t mu_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + pthread_cond_t cv_; + Mutex* mu_; +}; + +typedef pthread_once_t OnceType; +#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT +extern void InitOnce(OnceType* once, void (*initializer)()); + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc new file mode 100644 index 0000000..1b0f060 --- /dev/null +++ b/src/leveldb/port/port_win.cc @@ -0,0 +1,147 @@ +// LevelDB 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. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "port/port_win.h" + +#include +#include + +namespace leveldb { +namespace port { + +Mutex::Mutex() : + cs_(NULL) { + assert(!cs_); + cs_ = static_cast(new CRITICAL_SECTION()); + ::InitializeCriticalSection(static_cast(cs_)); + assert(cs_); +} + +Mutex::~Mutex() { + assert(cs_); + ::DeleteCriticalSection(static_cast(cs_)); + delete static_cast(cs_); + cs_ = NULL; + assert(!cs_); +} + +void Mutex::Lock() { + assert(cs_); + ::EnterCriticalSection(static_cast(cs_)); +} + +void Mutex::Unlock() { + assert(cs_); + ::LeaveCriticalSection(static_cast(cs_)); +} + +void Mutex::AssertHeld() { + assert(cs_); + assert(1); +} + +CondVar::CondVar(Mutex* mu) : + waiting_(0), + mu_(mu), + sem1_(::CreateSemaphore(NULL, 0, 10000, NULL)), + sem2_(::CreateSemaphore(NULL, 0, 10000, NULL)) { + assert(mu_); +} + +CondVar::~CondVar() { + ::CloseHandle(sem1_); + ::CloseHandle(sem2_); +} + +void CondVar::Wait() { + mu_->AssertHeld(); + + wait_mtx_.Lock(); + ++waiting_; + wait_mtx_.Unlock(); + + mu_->Unlock(); + + // initiate handshake + ::WaitForSingleObject(sem1_, INFINITE); + ::ReleaseSemaphore(sem2_, 1, NULL); + mu_->Lock(); +} + +void CondVar::Signal() { + wait_mtx_.Lock(); + if (waiting_ > 0) { + --waiting_; + + // finalize handshake + ::ReleaseSemaphore(sem1_, 1, NULL); + ::WaitForSingleObject(sem2_, INFINITE); + } + wait_mtx_.Unlock(); +} + +void CondVar::SignalAll() { + wait_mtx_.Lock(); + ::ReleaseSemaphore(sem1_, waiting_, NULL); + while(waiting_ > 0) { + --waiting_; + ::WaitForSingleObject(sem2_, INFINITE); + } + wait_mtx_.Unlock(); +} + +AtomicPointer::AtomicPointer(void* v) { + Release_Store(v); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + once->InitOnce(initializer); +} + +void* AtomicPointer::Acquire_Load() const { + void * p = NULL; + InterlockedExchangePointer(&p, rep_); + return p; +} + +void AtomicPointer::Release_Store(void* v) { + InterlockedExchangePointer(&rep_, v); +} + +void* AtomicPointer::NoBarrier_Load() const { + return rep_; +} + +void AtomicPointer::NoBarrier_Store(void* v) { + rep_ = v; +} + +} +} diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h new file mode 100644 index 0000000..45bf2f0 --- /dev/null +++ b/src/leveldb/port/port_win.h @@ -0,0 +1,174 @@ +// LevelDB 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. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ +#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ + +#ifdef _MSC_VER +#define snprintf _snprintf +#define close _close +#define fread_unlocked _fread_nolock +#endif + +#include +#include +#ifdef SNAPPY +#include +#endif + +namespace leveldb { +namespace port { + +// Windows is little endian (for now :p) +static const bool kLittleEndian = true; + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld(); + + private: + friend class CondVar; + // critical sections are more efficient than mutexes + // but they are not recursive and can only be used to synchronize threads within the same process + // we use opaque void * to avoid including windows.h in port_win.h + void * cs_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +// the Win32 API offers a dependable condition variable mechanism, but only starting with +// Windows 2008 and Vista +// no matter what we will implement our own condition variable with a semaphore +// implementation as described in a paper written by Andrew D. Birrell in 2003 +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + Mutex* mu_; + + Mutex wait_mtx_; + long waiting_; + + void * sem1_; + void * sem2_; + + +}; + +class OnceType { +public: +// OnceType() : init_(false) {} + OnceType(const OnceType &once) : init_(once.init_) {} + OnceType(bool f) : init_(f) {} + void InitOnce(void (*initializer)()) { + mutex_.Lock(); + if (!init_) { + init_ = true; + initializer(); + } + mutex_.Unlock(); + } + +private: + bool init_; + Mutex mutex_; +}; + +#define LEVELDB_ONCE_INIT false +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// Storage for a lock-free pointer +class AtomicPointer { + private: + void * rep_; + public: + AtomicPointer() : rep_(NULL) { } + explicit AtomicPointer(void* v); + void* Acquire_Load() const; + + void Release_Store(void* v); + + void* NoBarrier_Load() const; + + void NoBarrier_Store(void* v); +}; + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} +} + +#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ diff --git a/src/leveldb/port/thread_annotations.h b/src/leveldb/port/thread_annotations.h new file mode 100644 index 0000000..6f9b6a7 --- /dev/null +++ b/src/leveldb/port/thread_annotations.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012 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_PORT_THREAD_ANNOTATIONS_H + +// Some environments provide custom macros to aid in static thread-safety +// analysis. Provide empty definitions of such macros unless they are already +// defined. + +#ifndef EXCLUSIVE_LOCKS_REQUIRED +#define EXCLUSIVE_LOCKS_REQUIRED(...) +#endif + +#ifndef SHARED_LOCKS_REQUIRED +#define SHARED_LOCKS_REQUIRED(...) +#endif + +#ifndef LOCKS_EXCLUDED +#define LOCKS_EXCLUDED(...) +#endif + +#ifndef LOCK_RETURNED +#define LOCK_RETURNED(x) +#endif + +#ifndef LOCKABLE +#define LOCKABLE +#endif + +#ifndef SCOPED_LOCKABLE +#define SCOPED_LOCKABLE +#endif + +#ifndef EXCLUSIVE_LOCK_FUNCTION +#define EXCLUSIVE_LOCK_FUNCTION(...) +#endif + +#ifndef SHARED_LOCK_FUNCTION +#define SHARED_LOCK_FUNCTION(...) +#endif + +#ifndef EXCLUSIVE_TRYLOCK_FUNCTION +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) +#endif + +#ifndef SHARED_TRYLOCK_FUNCTION +#define SHARED_TRYLOCK_FUNCTION(...) +#endif + +#ifndef UNLOCK_FUNCTION +#define UNLOCK_FUNCTION(...) +#endif + +#ifndef NO_THREAD_SAFETY_ANALYSIS +#define NO_THREAD_SAFETY_ANALYSIS +#endif + +#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H diff --git a/src/leveldb/port/win/stdint.h b/src/leveldb/port/win/stdint.h new file mode 100644 index 0000000..39edd0d --- /dev/null +++ b/src/leveldb/port/win/stdint.h @@ -0,0 +1,24 @@ +// 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. + +// MSVC didn't ship with this file until the 2010 version. + +#ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_ +#define STORAGE_LEVELDB_PORT_WIN_STDINT_H_ + +#if !defined(_MSC_VER) +#error This file should only be included when compiling with MSVC. +#endif + +// Define C99 equivalent types. +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_ diff --git a/src/leveldb/table/block.cc b/src/leveldb/table/block.cc new file mode 100644 index 0000000..79ea9d9 --- /dev/null +++ b/src/leveldb/table/block.cc @@ -0,0 +1,268 @@ +// 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. +// +// Decodes the blocks generated by block_builder.cc. + +#include "table/block.h" + +#include +#include +#include "leveldb/comparator.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +inline uint32_t Block::NumRestarts() const { + assert(size_ >= sizeof(uint32_t)); + return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); +} + +Block::Block(const BlockContents& contents) + : data_(contents.data.data()), + size_(contents.data.size()), + owned_(contents.heap_allocated) { + if (size_ < sizeof(uint32_t)) { + size_ = 0; // Error marker + } else { + size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t); + if (NumRestarts() > max_restarts_allowed) { + // The size is too small for NumRestarts() + size_ = 0; + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); + } + } +} + +Block::~Block() { + if (owned_) { + delete[] data_; + } +} + +// Helper routine: decode the next block entry starting at "p", +// storing the number of shared key bytes, non_shared key bytes, +// and the length of the value in "*shared", "*non_shared", and +// "*value_length", respectively. Will not derefence past "limit". +// +// If any errors are detected, returns NULL. Otherwise, returns a +// pointer to the key delta (just past the three decoded values). +static inline const char* DecodeEntry(const char* p, const char* limit, + uint32_t* shared, + uint32_t* non_shared, + uint32_t* value_length) { + if (limit - p < 3) return NULL; + *shared = reinterpret_cast(p)[0]; + *non_shared = reinterpret_cast(p)[1]; + *value_length = reinterpret_cast(p)[2]; + if ((*shared | *non_shared | *value_length) < 128) { + // Fast path: all three values are encoded in one byte each + p += 3; + } else { + if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL; + } + + if (static_cast(limit - p) < (*non_shared + *value_length)) { + return NULL; + } + return p; +} + +class Block::Iter : public Iterator { + private: + const Comparator* const comparator_; + const char* const data_; // underlying block contents + uint32_t const restarts_; // Offset of restart array (list of fixed32) + uint32_t const num_restarts_; // Number of uint32_t entries in restart array + + // current_ is offset in data_ of current entry. >= restarts_ if !Valid + uint32_t current_; + uint32_t restart_index_; // Index of restart block in which current_ falls + std::string key_; + Slice value_; + Status status_; + + inline int Compare(const Slice& a, const Slice& b) const { + return comparator_->Compare(a, b); + } + + // Return the offset in data_ just past the end of the current entry. + inline uint32_t NextEntryOffset() const { + return (value_.data() + value_.size()) - data_; + } + + uint32_t GetRestartPoint(uint32_t index) { + assert(index < num_restarts_); + return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); + } + + void SeekToRestartPoint(uint32_t index) { + key_.clear(); + restart_index_ = index; + // current_ will be fixed by ParseNextKey(); + + // ParseNextKey() starts at the end of value_, so set value_ accordingly + uint32_t offset = GetRestartPoint(index); + value_ = Slice(data_ + offset, 0); + } + + public: + Iter(const Comparator* comparator, + const char* data, + uint32_t restarts, + uint32_t num_restarts) + : comparator_(comparator), + data_(data), + restarts_(restarts), + num_restarts_(num_restarts), + current_(restarts_), + restart_index_(num_restarts_) { + assert(num_restarts_ > 0); + } + + virtual bool Valid() const { return current_ < restarts_; } + virtual Status status() const { return status_; } + virtual Slice key() const { + assert(Valid()); + return key_; + } + virtual Slice value() const { + assert(Valid()); + return value_; + } + + virtual void Next() { + assert(Valid()); + ParseNextKey(); + } + + virtual void Prev() { + assert(Valid()); + + // Scan backwards to a restart point before current_ + const uint32_t original = current_; + while (GetRestartPoint(restart_index_) >= original) { + if (restart_index_ == 0) { + // No more entries + current_ = restarts_; + restart_index_ = num_restarts_; + return; + } + restart_index_--; + } + + SeekToRestartPoint(restart_index_); + do { + // Loop until end of current entry hits the start of original entry + } while (ParseNextKey() && NextEntryOffset() < original); + } + + virtual void Seek(const Slice& target) { + // Binary search in restart array to find the last restart point + // with a key < target + uint32_t left = 0; + uint32_t right = num_restarts_ - 1; + while (left < right) { + uint32_t mid = (left + right + 1) / 2; + uint32_t region_offset = GetRestartPoint(mid); + uint32_t shared, non_shared, value_length; + const char* key_ptr = DecodeEntry(data_ + region_offset, + data_ + restarts_, + &shared, &non_shared, &value_length); + if (key_ptr == NULL || (shared != 0)) { + CorruptionError(); + return; + } + Slice mid_key(key_ptr, non_shared); + if (Compare(mid_key, target) < 0) { + // Key at "mid" is smaller than "target". Therefore all + // blocks before "mid" are uninteresting. + left = mid; + } else { + // Key at "mid" is >= "target". Therefore all blocks at or + // after "mid" are uninteresting. + right = mid - 1; + } + } + + // Linear search (within restart block) for first key >= target + SeekToRestartPoint(left); + while (true) { + if (!ParseNextKey()) { + return; + } + if (Compare(key_, target) >= 0) { + return; + } + } + } + + virtual void SeekToFirst() { + SeekToRestartPoint(0); + ParseNextKey(); + } + + virtual void SeekToLast() { + SeekToRestartPoint(num_restarts_ - 1); + while (ParseNextKey() && NextEntryOffset() < restarts_) { + // Keep skipping + } + } + + private: + void CorruptionError() { + current_ = restarts_; + restart_index_ = num_restarts_; + status_ = Status::Corruption("bad entry in block"); + key_.clear(); + value_.clear(); + } + + bool ParseNextKey() { + current_ = NextEntryOffset(); + const char* p = data_ + current_; + const char* limit = data_ + restarts_; // Restarts come right after data + if (p >= limit) { + // No more entries to return. Mark as invalid. + current_ = restarts_; + restart_index_ = num_restarts_; + return false; + } + + // Decode next entry + uint32_t shared, non_shared, value_length; + p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); + if (p == NULL || key_.size() < shared) { + CorruptionError(); + return false; + } else { + key_.resize(shared); + key_.append(p, non_shared); + value_ = Slice(p + non_shared, value_length); + while (restart_index_ + 1 < num_restarts_ && + GetRestartPoint(restart_index_ + 1) < current_) { + ++restart_index_; + } + return true; + } + } +}; + +Iterator* Block::NewIterator(const Comparator* cmp) { + if (size_ < sizeof(uint32_t)) { + return NewErrorIterator(Status::Corruption("bad block contents")); + } + const uint32_t num_restarts = NumRestarts(); + if (num_restarts == 0) { + return NewEmptyIterator(); + } else { + return new Iter(cmp, data_, restart_offset_, num_restarts); + } +} + +} // namespace leveldb diff --git a/src/leveldb/table/block.h b/src/leveldb/table/block.h new file mode 100644 index 0000000..2493eb9 --- /dev/null +++ b/src/leveldb/table/block.h @@ -0,0 +1,44 @@ +// 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_TABLE_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_H_ + +#include +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +struct BlockContents; +class Comparator; + +class Block { + public: + // Initialize the block with the specified contents. + explicit Block(const BlockContents& contents); + + ~Block(); + + size_t size() const { return size_; } + Iterator* NewIterator(const Comparator* comparator); + + private: + uint32_t NumRestarts() const; + + const char* data_; + size_t size_; + uint32_t restart_offset_; // Offset in data_ of restart array + bool owned_; // Block owns data_[] + + // No copying allowed + Block(const Block&); + void operator=(const Block&); + + class Iter; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/src/leveldb/table/block_builder.cc b/src/leveldb/table/block_builder.cc new file mode 100644 index 0000000..db660cd --- /dev/null +++ b/src/leveldb/table/block_builder.cc @@ -0,0 +1,109 @@ +// 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. +// +// BlockBuilder generates blocks where keys are prefix-compressed: +// +// When we store a key, we drop the prefix shared with the previous +// string. This helps reduce the space requirement significantly. +// Furthermore, once every K keys, we do not apply the prefix +// compression and store the entire key. We call this a "restart +// point". The tail end of the block stores the offsets of all of the +// restart points, and can be used to do a binary search when looking +// for a particular key. Values are stored as-is (without compression) +// immediately following the corresponding key. +// +// An entry for a particular key-value pair has the form: +// shared_bytes: varint32 +// unshared_bytes: varint32 +// value_length: varint32 +// key_delta: char[unshared_bytes] +// value: char[value_length] +// shared_bytes == 0 for restart points. +// +// The trailer of the block has the form: +// restarts: uint32[num_restarts] +// num_restarts: uint32 +// restarts[i] contains the offset within the block of the ith restart point. + +#include "table/block_builder.h" + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" + +namespace leveldb { + +BlockBuilder::BlockBuilder(const Options* options) + : options_(options), + restarts_(), + counter_(0), + finished_(false) { + assert(options->block_restart_interval >= 1); + restarts_.push_back(0); // First restart point is at offset 0 +} + +void BlockBuilder::Reset() { + buffer_.clear(); + restarts_.clear(); + restarts_.push_back(0); // First restart point is at offset 0 + counter_ = 0; + finished_ = false; + last_key_.clear(); +} + +size_t BlockBuilder::CurrentSizeEstimate() const { + return (buffer_.size() + // Raw data buffer + restarts_.size() * sizeof(uint32_t) + // Restart array + sizeof(uint32_t)); // Restart array length +} + +Slice BlockBuilder::Finish() { + // Append restart array + for (size_t i = 0; i < restarts_.size(); i++) { + PutFixed32(&buffer_, restarts_[i]); + } + PutFixed32(&buffer_, restarts_.size()); + finished_ = true; + return Slice(buffer_); +} + +void BlockBuilder::Add(const Slice& key, const Slice& value) { + Slice last_key_piece(last_key_); + assert(!finished_); + assert(counter_ <= options_->block_restart_interval); + assert(buffer_.empty() // No values yet? + || options_->comparator->Compare(key, last_key_piece) > 0); + size_t shared = 0; + if (counter_ < options_->block_restart_interval) { + // See how much sharing to do with previous string + const size_t min_length = std::min(last_key_piece.size(), key.size()); + while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { + shared++; + } + } else { + // Restart compression + restarts_.push_back(buffer_.size()); + counter_ = 0; + } + const size_t non_shared = key.size() - shared; + + // Add "" to buffer_ + PutVarint32(&buffer_, shared); + PutVarint32(&buffer_, non_shared); + PutVarint32(&buffer_, value.size()); + + // Add string delta to buffer_ followed by value + buffer_.append(key.data() + shared, non_shared); + buffer_.append(value.data(), value.size()); + + // Update state + last_key_.resize(shared); + last_key_.append(key.data() + shared, non_shared); + assert(Slice(last_key_) == key); + counter_++; +} + +} // namespace leveldb diff --git a/src/leveldb/table/block_builder.h b/src/leveldb/table/block_builder.h new file mode 100644 index 0000000..5b545bd --- /dev/null +++ b/src/leveldb/table/block_builder.h @@ -0,0 +1,57 @@ +// 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_TABLE_BLOCK_BUILDER_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ + +#include + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +struct Options; + +class BlockBuilder { + public: + explicit BlockBuilder(const Options* options); + + // Reset the contents as if the BlockBuilder was just constructed. + void Reset(); + + // REQUIRES: Finish() has not been callled since the last call to Reset(). + // REQUIRES: key is larger than any previously added key + void Add(const Slice& key, const Slice& value); + + // Finish building the block and return a slice that refers to the + // block contents. The returned slice will remain valid for the + // lifetime of this builder or until Reset() is called. + Slice Finish(); + + // Returns an estimate of the current (uncompressed) size of the block + // we are building. + size_t CurrentSizeEstimate() const; + + // Return true iff no entries have been added since the last Reset() + bool empty() const { + return buffer_.empty(); + } + + private: + const Options* options_; + std::string buffer_; // Destination buffer + std::vector restarts_; // Restart points + int counter_; // Number of entries emitted since restart + bool finished_; // Has Finish() been called? + std::string last_key_; + + // No copying allowed + BlockBuilder(const BlockBuilder&); + void operator=(const BlockBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/src/leveldb/table/filter_block.cc b/src/leveldb/table/filter_block.cc new file mode 100644 index 0000000..203e15c --- /dev/null +++ b/src/leveldb/table/filter_block.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2012 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 "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" + +namespace leveldb { + +// See doc/table_format.txt for an explanation of the filter block format. + +// Generate new filter every 2KB of data +static const size_t kFilterBaseLg = 11; +static const size_t kFilterBase = 1 << kFilterBaseLg; + +FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) + : policy_(policy) { +} + +void FilterBlockBuilder::StartBlock(uint64_t block_offset) { + uint64_t filter_index = (block_offset / kFilterBase); + assert(filter_index >= filter_offsets_.size()); + while (filter_index > filter_offsets_.size()) { + GenerateFilter(); + } +} + +void FilterBlockBuilder::AddKey(const Slice& key) { + Slice k = key; + start_.push_back(keys_.size()); + keys_.append(k.data(), k.size()); +} + +Slice FilterBlockBuilder::Finish() { + if (!start_.empty()) { + GenerateFilter(); + } + + // Append array of per-filter offsets + const uint32_t array_offset = result_.size(); + for (size_t i = 0; i < filter_offsets_.size(); i++) { + PutFixed32(&result_, filter_offsets_[i]); + } + + PutFixed32(&result_, array_offset); + result_.push_back(kFilterBaseLg); // Save encoding parameter in result + return Slice(result_); +} + +void FilterBlockBuilder::GenerateFilter() { + const size_t num_keys = start_.size(); + if (num_keys == 0) { + // Fast path if there are no keys for this filter + filter_offsets_.push_back(result_.size()); + return; + } + + // Make list of keys from flattened key structure + start_.push_back(keys_.size()); // Simplify length computation + tmp_keys_.resize(num_keys); + for (size_t i = 0; i < num_keys; i++) { + const char* base = keys_.data() + start_[i]; + size_t length = start_[i+1] - start_[i]; + tmp_keys_[i] = Slice(base, length); + } + + // 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_); + + tmp_keys_.clear(); + keys_.clear(); + start_.clear(); +} + +FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, + const Slice& contents) + : policy_(policy), + data_(NULL), + offset_(NULL), + num_(0), + base_lg_(0) { + size_t n = contents.size(); + if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array + base_lg_ = contents[n-1]; + uint32_t last_word = DecodeFixed32(contents.data() + n - 5); + if (last_word > n - 5) return; + data_ = contents.data(); + offset_ = data_ + last_word; + num_ = (n - 5 - last_word) / 4; +} + +bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { + uint64_t index = block_offset >> base_lg_; + if (index < num_) { + uint32_t start = DecodeFixed32(offset_ + index*4); + uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); + if (start <= limit && limit <= (offset_ - data_)) { + Slice filter = Slice(data_ + start, limit - start); + return policy_->KeyMayMatch(key, filter); + } else if (start == limit) { + // Empty filters do not match any keys + return false; + } + } + return true; // Errors are treated as potential matches +} + +} diff --git a/src/leveldb/table/filter_block.h b/src/leveldb/table/filter_block.h new file mode 100644 index 0000000..c67d010 --- /dev/null +++ b/src/leveldb/table/filter_block.h @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A filter block is stored near the end of a Table file. It contains +// filters (e.g., bloom filters) for all data blocks in the table combined +// into a single filter block. + +#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ + +#include +#include +#include +#include +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +class FilterPolicy; + +// A FilterBlockBuilder is used to construct all of the filters for a +// particular Table. It generates a single string which is stored as +// a special block in the Table. +// +// The sequence of calls to FilterBlockBuilder must match the regexp: +// (StartBlock AddKey*)* Finish +class FilterBlockBuilder { + public: + explicit FilterBlockBuilder(const FilterPolicy*); + + void StartBlock(uint64_t block_offset); + void AddKey(const Slice& key); + Slice Finish(); + + private: + void GenerateFilter(); + + const FilterPolicy* policy_; + std::string keys_; // Flattened key contents + std::vector start_; // Starting index in keys_ of each key + std::string result_; // Filter data computed so far + std::vector tmp_keys_; // policy_->CreateFilter() argument + std::vector filter_offsets_; + + // No copying allowed + FilterBlockBuilder(const FilterBlockBuilder&); + void operator=(const FilterBlockBuilder&); +}; + +class FilterBlockReader { + public: + // REQUIRES: "contents" and *policy must stay live while *this is live. + FilterBlockReader(const FilterPolicy* policy, const Slice& contents); + bool KeyMayMatch(uint64_t block_offset, const Slice& key); + + private: + const FilterPolicy* policy_; + const char* data_; // Pointer to filter data (at block-start) + const char* offset_; // Pointer to beginning of offset array (at block-end) + size_t num_; // Number of entries in offset array + size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) +}; + +} + +#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/src/leveldb/table/filter_block_test.cc b/src/leveldb/table/filter_block_test.cc new file mode 100644 index 0000000..3a2a07c --- /dev/null +++ b/src/leveldb/table/filter_block_test.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2012 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 "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// For testing: emit an array with one hash value per key +class TestHashFilter : public FilterPolicy { + public: + virtual const char* Name() const { + return "TestHashFilter"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + for (int i = 0; i < n; i++) { + uint32_t h = Hash(keys[i].data(), keys[i].size(), 1); + PutFixed32(dst, h); + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + uint32_t h = Hash(key.data(), key.size(), 1); + for (int i = 0; i + 4 <= filter.size(); i += 4) { + if (h == DecodeFixed32(filter.data() + i)) { + return true; + } + } + return false; + } +}; + +class FilterBlockTest { + public: + TestHashFilter policy_; +}; + +TEST(FilterBlockTest, EmptyBuilder) { + FilterBlockBuilder builder(&policy_); + Slice block = builder.Finish(); + ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block)); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100000, "foo")); +} + +TEST(FilterBlockTest, SingleChunk) { + FilterBlockBuilder builder(&policy_); + builder.StartBlock(100); + builder.AddKey("foo"); + builder.AddKey("bar"); + builder.AddKey("box"); + builder.StartBlock(200); + builder.AddKey("box"); + builder.StartBlock(300); + builder.AddKey("hello"); + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100, "bar")); + ASSERT_TRUE(reader.KeyMayMatch(100, "box")); + ASSERT_TRUE(reader.KeyMayMatch(100, "hello")); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "missing")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "other")); +} + +TEST(FilterBlockTest, MultiChunk) { + FilterBlockBuilder builder(&policy_); + + // First filter + builder.StartBlock(0); + builder.AddKey("foo"); + builder.StartBlock(2000); + builder.AddKey("bar"); + + // Second filter + builder.StartBlock(3100); + builder.AddKey("box"); + + // Third filter is empty + + // Last filter + builder.StartBlock(9000); + builder.AddKey("box"); + builder.AddKey("hello"); + + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + + // Check first filter + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(2000, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "hello")); + + // Check second filter + ASSERT_TRUE(reader.KeyMayMatch(3100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "hello")); + + // Check third filter (empty) + ASSERT_TRUE(! reader.KeyMayMatch(4100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "hello")); + + // Check last filter + ASSERT_TRUE(reader.KeyMayMatch(9000, "box")); + ASSERT_TRUE(reader.KeyMayMatch(9000, "hello")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "bar")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc new file mode 100644 index 0000000..cda1dec --- /dev/null +++ b/src/leveldb/table/format.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/format.h" + +#include "leveldb/env.h" +#include "port/port.h" +#include "table/block.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +void BlockHandle::EncodeTo(std::string* dst) const { + // Sanity check that all fields have been set + assert(offset_ != ~static_cast(0)); + assert(size_ != ~static_cast(0)); + PutVarint64(dst, offset_); + PutVarint64(dst, size_); +} + +Status BlockHandle::DecodeFrom(Slice* input) { + if (GetVarint64(input, &offset_) && + GetVarint64(input, &size_)) { + return Status::OK(); + } else { + return Status::Corruption("bad block handle"); + } +} + +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(kTableMagicNumber & 0xffffffffu)); + PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); + assert(dst->size() == original_size + kEncodedLength); +} + +Status Footer::DecodeFrom(Slice* input) { + const char* magic_ptr = input->data() + kEncodedLength - 8; + const uint32_t magic_lo = DecodeFixed32(magic_ptr); + const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); + const uint64_t magic = ((static_cast(magic_hi) << 32) | + (static_cast(magic_lo))); + if (magic != kTableMagicNumber) { + return Status::InvalidArgument("not an sstable (bad magic number)"); + } + + Status result = metaindex_handle_.DecodeFrom(input); + if (result.ok()) { + result = index_handle_.DecodeFrom(input); + } + if (result.ok()) { + // We skip over any leftover data (just padding for now) in "input" + const char* end = magic_ptr + 8; + *input = Slice(end, input->data() + input->size() - end); + } + return result; +} + +Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result) { + result->data = Slice(); + result->cachable = false; + result->heap_allocated = false; + + // Read the block contents as well as the type/crc footer. + // See table_builder.cc for the code that built this structure. + size_t n = static_cast(handle.size()); + char* buf = new char[n + kBlockTrailerSize]; + Slice contents; + Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); + if (!s.ok()) { + delete[] buf; + return s; + } + if (contents.size() != n + kBlockTrailerSize) { + delete[] buf; + return Status::Corruption("truncated block read"); + } + + // Check the crc of the type and the block contents + const char* data = contents.data(); // Pointer to where Read put the data + if (options.verify_checksums) { + const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); + const uint32_t actual = crc32c::Value(data, n + 1); + if (actual != crc) { + delete[] buf; + s = Status::Corruption("block checksum mismatch"); + return s; + } + } + + switch (data[n]) { + case kNoCompression: + if (data != buf) { + // File implementation gave us pointer to some other data. + // Use it directly under the assumption that it will be live + // while the file is open. + delete[] buf; + result->data = Slice(data, n); + result->heap_allocated = false; + result->cachable = false; // Do not double-cache + } else { + result->data = Slice(buf, n); + result->heap_allocated = true; + result->cachable = true; + } + + // Ok + break; + case kSnappyCompression: { + size_t ulength = 0; + if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { + delete[] buf; + return Status::Corruption("corrupted compressed block contents"); + } + char* ubuf = new char[ulength]; + if (!port::Snappy_Uncompress(data, n, ubuf)) { + delete[] buf; + delete[] ubuf; + return Status::Corruption("corrupted compressed block contents"); + } + delete[] buf; + result->data = Slice(ubuf, ulength); + result->heap_allocated = true; + result->cachable = true; + break; + } + default: + delete[] buf; + return Status::Corruption("bad block type"); + } + + return Status::OK(); +} + +} // namespace leveldb diff --git a/src/leveldb/table/format.h b/src/leveldb/table/format.h new file mode 100644 index 0000000..6c0b80c --- /dev/null +++ b/src/leveldb/table/format.h @@ -0,0 +1,108 @@ +// 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_TABLE_FORMAT_H_ +#define STORAGE_LEVELDB_TABLE_FORMAT_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "leveldb/table_builder.h" + +namespace leveldb { + +class Block; +class RandomAccessFile; +struct ReadOptions; + +// BlockHandle is a pointer to the extent of a file that stores a data +// block or a meta block. +class BlockHandle { + public: + BlockHandle(); + + // The offset of the block in the file. + uint64_t offset() const { return offset_; } + void set_offset(uint64_t offset) { offset_ = offset; } + + // The size of the stored block + uint64_t size() const { return size_; } + void set_size(uint64_t size) { size_ = size; } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Maximum encoding length of a BlockHandle + enum { kMaxEncodedLength = 10 + 10 }; + + private: + uint64_t offset_; + uint64_t size_; +}; + +// Footer encapsulates the fixed information stored at the tail +// end of every table file. +class Footer { + public: + Footer() { } + + // The block handle for the metaindex block of the table + const BlockHandle& metaindex_handle() const { return metaindex_handle_; } + void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } + + // The block handle for the index block of the table + const BlockHandle& index_handle() const { + return index_handle_; + } + void set_index_handle(const BlockHandle& h) { + index_handle_ = h; + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Encoded length of a Footer. Note that the serialization of a + // Footer will always occupy exactly this many bytes. It consists + // of two block handles and a magic number. + enum { + kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8 + }; + + private: + BlockHandle metaindex_handle_; + BlockHandle index_handle_; +}; + +// kTableMagicNumber was picked by running +// echo http://code.google.com/p/leveldb/ | sha1sum +// and taking the leading 64 bits. +static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; + +// 1-byte type + 32-bit crc +static const size_t kBlockTrailerSize = 5; + +struct BlockContents { + Slice data; // Actual contents of data + bool cachable; // True iff data can be cached + bool heap_allocated; // True iff caller should delete[] data.data() +}; + +// Read the block identified by "handle" from "file". On failure +// return non-OK. On success fill *result and return OK. +extern Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result); + +// Implementation details follow. Clients should ignore, + +inline BlockHandle::BlockHandle() + : offset_(~static_cast(0)), + size_(~static_cast(0)) { +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/src/leveldb/table/iterator.cc b/src/leveldb/table/iterator.cc new file mode 100644 index 0000000..3d1c87f --- /dev/null +++ b/src/leveldb/table/iterator.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/iterator.h" + +namespace leveldb { + +Iterator::Iterator() { + cleanup_.function = NULL; + cleanup_.next = NULL; +} + +Iterator::~Iterator() { + if (cleanup_.function != NULL) { + (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2); + for (Cleanup* c = cleanup_.next; c != NULL; ) { + (*c->function)(c->arg1, c->arg2); + Cleanup* next = c->next; + delete c; + c = next; + } + } +} + +void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { + assert(func != NULL); + Cleanup* c; + if (cleanup_.function == NULL) { + c = &cleanup_; + } else { + c = new Cleanup; + c->next = cleanup_.next; + cleanup_.next = c; + } + c->function = func; + c->arg1 = arg1; + c->arg2 = arg2; +} + +namespace { +class EmptyIterator : public Iterator { + public: + EmptyIterator(const Status& s) : status_(s) { } + virtual bool Valid() const { return false; } + virtual void Seek(const Slice& target) { } + virtual void SeekToFirst() { } + virtual void SeekToLast() { } + virtual void Next() { assert(false); } + virtual void Prev() { assert(false); } + Slice key() const { assert(false); return Slice(); } + Slice value() const { assert(false); return Slice(); } + virtual Status status() const { return status_; } + private: + Status status_; +}; +} // namespace + +Iterator* NewEmptyIterator() { + return new EmptyIterator(Status::OK()); +} + +Iterator* NewErrorIterator(const Status& status) { + return new EmptyIterator(status); +} + +} // namespace leveldb diff --git a/src/leveldb/table/iterator_wrapper.h b/src/leveldb/table/iterator_wrapper.h new file mode 100644 index 0000000..9e16b3d --- /dev/null +++ b/src/leveldb/table/iterator_wrapper.h @@ -0,0 +1,63 @@ +// 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_TABLE_ITERATOR_WRAPPER_H_ +#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ + +namespace leveldb { + +// A internal wrapper class with an interface similar to Iterator that +// caches the valid() and key() results for an underlying iterator. +// This can help avoid virtual function calls and also gives better +// cache locality. +class IteratorWrapper { + public: + IteratorWrapper(): iter_(NULL), valid_(false) { } + explicit IteratorWrapper(Iterator* iter): iter_(NULL) { + Set(iter); + } + ~IteratorWrapper() { delete iter_; } + Iterator* iter() const { return iter_; } + + // Takes ownership of "iter" and will delete it when destroyed, or + // when Set() is invoked again. + void Set(Iterator* iter) { + delete iter_; + iter_ = iter; + if (iter_ == NULL) { + valid_ = false; + } else { + Update(); + } + } + + + // Iterator interface methods + bool Valid() const { return valid_; } + Slice key() const { assert(Valid()); return key_; } + Slice value() const { assert(Valid()); return iter_->value(); } + // Methods below require iter() != NULL + Status status() const { assert(iter_); return iter_->status(); } + void Next() { assert(iter_); iter_->Next(); Update(); } + void Prev() { assert(iter_); iter_->Prev(); Update(); } + void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } + void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } + void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } + + private: + void Update() { + valid_ = iter_->Valid(); + if (valid_) { + key_ = iter_->key(); + } + } + + Iterator* iter_; + bool valid_; + Slice key_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/src/leveldb/table/merger.cc b/src/leveldb/table/merger.cc new file mode 100644 index 0000000..2dde4dc --- /dev/null +++ b/src/leveldb/table/merger.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/merger.h" + +#include "leveldb/comparator.h" +#include "leveldb/iterator.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { +class MergingIterator : public Iterator { + public: + MergingIterator(const Comparator* comparator, Iterator** children, int n) + : comparator_(comparator), + children_(new IteratorWrapper[n]), + n_(n), + current_(NULL), + direction_(kForward) { + for (int i = 0; i < n; i++) { + children_[i].Set(children[i]); + } + } + + virtual ~MergingIterator() { + delete[] children_; + } + + virtual bool Valid() const { + return (current_ != NULL); + } + + virtual void SeekToFirst() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToFirst(); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void SeekToLast() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToLast(); + } + FindLargest(); + direction_ = kReverse; + } + + virtual void Seek(const Slice& target) { + for (int i = 0; i < n_; i++) { + children_[i].Seek(target); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void Next() { + assert(Valid()); + + // Ensure that all children are positioned after key(). + // If we are moving in the forward direction, it is already + // true for all of the non-current_ children since current_ is + // the smallest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kForward) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid() && + comparator_->Compare(key(), child->key()) == 0) { + child->Next(); + } + } + } + direction_ = kForward; + } + + current_->Next(); + FindSmallest(); + } + + virtual void Prev() { + assert(Valid()); + + // Ensure that all children are positioned before key(). + // If we are moving in the reverse direction, it is already + // true for all of the non-current_ children since current_ is + // the largest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kReverse) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid()) { + // Child is at first entry >= key(). Step back one to be < key() + child->Prev(); + } else { + // Child has no entries >= key(). Position at last entry. + child->SeekToLast(); + } + } + } + direction_ = kReverse; + } + + current_->Prev(); + FindLargest(); + } + + virtual Slice key() const { + assert(Valid()); + return current_->key(); + } + + virtual Slice value() const { + assert(Valid()); + return current_->value(); + } + + virtual Status status() const { + Status status; + for (int i = 0; i < n_; i++) { + status = children_[i].status(); + if (!status.ok()) { + break; + } + } + return status; + } + + private: + void FindSmallest(); + void FindLargest(); + + // We might want to use a heap in case there are lots of children. + // For now we use a simple array since we expect a very small number + // of children in leveldb. + const Comparator* comparator_; + IteratorWrapper* children_; + int n_; + IteratorWrapper* current_; + + // Which direction is the iterator moving? + enum Direction { + kForward, + kReverse + }; + Direction direction_; +}; + +void MergingIterator::FindSmallest() { + IteratorWrapper* smallest = NULL; + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (smallest == NULL) { + smallest = child; + } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { + smallest = child; + } + } + } + current_ = smallest; +} + +void MergingIterator::FindLargest() { + IteratorWrapper* largest = NULL; + for (int i = n_-1; i >= 0; i--) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (largest == NULL) { + largest = child; + } else if (comparator_->Compare(child->key(), largest->key()) > 0) { + largest = child; + } + } + } + current_ = largest; +} +} // namespace + +Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) { + assert(n >= 0); + if (n == 0) { + return NewEmptyIterator(); + } else if (n == 1) { + return list[0]; + } else { + return new MergingIterator(cmp, list, n); + } +} + +} // namespace leveldb diff --git a/src/leveldb/table/merger.h b/src/leveldb/table/merger.h new file mode 100644 index 0000000..91ddd80 --- /dev/null +++ b/src/leveldb/table/merger.h @@ -0,0 +1,26 @@ +// 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_TABLE_MERGER_H_ +#define STORAGE_LEVELDB_TABLE_MERGER_H_ + +namespace leveldb { + +class Comparator; +class Iterator; + +// Return an iterator that provided the union of the data in +// children[0,n-1]. Takes ownership of the child iterators and +// will delete them when the result iterator is deleted. +// +// The result does no duplicate suppression. I.e., if a particular +// key is present in K child iterators, it will be yielded K times. +// +// REQUIRES: n >= 0 +extern Iterator* NewMergingIterator( + const Comparator* comparator, Iterator** children, int n); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc new file mode 100644 index 0000000..71c1756 --- /dev/null +++ b/src/leveldb/table/table.cc @@ -0,0 +1,275 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" + +namespace leveldb { + +struct Table::Rep { + ~Rep() { + delete filter; + delete [] filter_data; + delete index_block; + } + + Options options; + Status status; + RandomAccessFile* file; + uint64_t cache_id; + FilterBlockReader* filter; + const char* filter_data; + + BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer + Block* index_block; +}; + +Status Table::Open(const Options& options, + RandomAccessFile* file, + uint64_t size, + Table** table) { + *table = NULL; + if (size < Footer::kEncodedLength) { + return Status::InvalidArgument("file is too short to be an sstable"); + } + + char footer_space[Footer::kEncodedLength]; + Slice footer_input; + Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, + &footer_input, footer_space); + if (!s.ok()) return s; + + Footer footer; + s = footer.DecodeFrom(&footer_input); + if (!s.ok()) return s; + + // Read the index block + BlockContents contents; + Block* index_block = NULL; + if (s.ok()) { + s = ReadBlock(file, ReadOptions(), footer.index_handle(), &contents); + if (s.ok()) { + index_block = new Block(contents); + } + } + + if (s.ok()) { + // We've successfully read the footer and the index block: we're + // ready to serve requests. + Rep* rep = new Table::Rep; + rep->options = options; + rep->file = file; + rep->metaindex_handle = footer.metaindex_handle(); + rep->index_block = index_block; + rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); + rep->filter_data = NULL; + rep->filter = NULL; + *table = new Table(rep); + (*table)->ReadMeta(footer); + } else { + if (index_block) delete index_block; + } + + return s; +} + +void Table::ReadMeta(const Footer& footer) { + if (rep_->options.filter_policy == NULL) { + return; // Do not need any metadata + } + + // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates + // it is an empty block. + ReadOptions opt; + BlockContents contents; + if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { + // Do not propagate errors since meta info is not needed for operation + return; + } + Block* meta = new Block(contents); + + Iterator* iter = meta->NewIterator(BytewiseComparator()); + std::string key = "filter."; + key.append(rep_->options.filter_policy->Name()); + iter->Seek(key); + if (iter->Valid() && iter->key() == Slice(key)) { + ReadFilter(iter->value()); + } + delete iter; + delete meta; +} + +void Table::ReadFilter(const Slice& filter_handle_value) { + Slice v = filter_handle_value; + BlockHandle filter_handle; + if (!filter_handle.DecodeFrom(&v).ok()) { + return; + } + + // We might want to unify with ReadBlock() if we start + // requiring checksum verification in Table::Open. + ReadOptions opt; + BlockContents block; + if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { + return; + } + if (block.heap_allocated) { + rep_->filter_data = block.data.data(); // Will need to delete later + } + rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); +} + +Table::~Table() { + delete rep_; +} + +static void DeleteBlock(void* arg, void* ignored) { + delete reinterpret_cast(arg); +} + +static void DeleteCachedBlock(const Slice& key, void* value) { + Block* block = reinterpret_cast(value); + delete block; +} + +static void ReleaseBlock(void* arg, void* h) { + Cache* cache = reinterpret_cast(arg); + Cache::Handle* handle = reinterpret_cast(h); + cache->Release(handle); +} + +// Convert an index iterator value (i.e., an encoded BlockHandle) +// into an iterator over the contents of the corresponding block. +Iterator* Table::BlockReader(void* arg, + const ReadOptions& options, + const Slice& index_value) { + Table* table = reinterpret_cast(arg); + Cache* block_cache = table->rep_->options.block_cache; + Block* block = NULL; + Cache::Handle* cache_handle = NULL; + + BlockHandle handle; + Slice input = index_value; + Status s = handle.DecodeFrom(&input); + // We intentionally allow extra stuff in index_value so that we + // can add more features in the future. + + if (s.ok()) { + BlockContents contents; + if (block_cache != NULL) { + char cache_key_buffer[16]; + EncodeFixed64(cache_key_buffer, table->rep_->cache_id); + EncodeFixed64(cache_key_buffer+8, handle.offset()); + Slice key(cache_key_buffer, sizeof(cache_key_buffer)); + cache_handle = block_cache->Lookup(key); + if (cache_handle != NULL) { + block = reinterpret_cast(block_cache->Value(cache_handle)); + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + if (contents.cachable && options.fill_cache) { + cache_handle = block_cache->Insert( + key, block, block->size(), &DeleteCachedBlock); + } + } + } + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + } + } + } + + Iterator* iter; + if (block != NULL) { + iter = block->NewIterator(table->rep_->options.comparator); + if (cache_handle == NULL) { + iter->RegisterCleanup(&DeleteBlock, block, NULL); + } else { + iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); + } + } else { + iter = NewErrorIterator(s); + } + return iter; +} + +Iterator* Table::NewIterator(const ReadOptions& options) const { + return NewTwoLevelIterator( + rep_->index_block->NewIterator(rep_->options.comparator), + &Table::BlockReader, const_cast(this), options); +} + +Status Table::InternalGet(const ReadOptions& options, const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Status s; + Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); + iiter->Seek(k); + if (iiter->Valid()) { + Slice handle_value = iiter->value(); + FilterBlockReader* filter = rep_->filter; + BlockHandle handle; + if (filter != NULL && + handle.DecodeFrom(&handle_value).ok() && + !filter->KeyMayMatch(handle.offset(), k)) { + // Not found + } else { + Iterator* block_iter = BlockReader(this, options, iiter->value()); + block_iter->Seek(k); + if (block_iter->Valid()) { + (*saver)(arg, block_iter->key(), block_iter->value()); + } + s = block_iter->status(); + delete block_iter; + } + } + if (s.ok()) { + s = iiter->status(); + } + delete iiter; + return s; +} + + +uint64_t Table::ApproximateOffsetOf(const Slice& key) const { + Iterator* index_iter = + rep_->index_block->NewIterator(rep_->options.comparator); + index_iter->Seek(key); + uint64_t result; + if (index_iter->Valid()) { + BlockHandle handle; + Slice input = index_iter->value(); + Status s = handle.DecodeFrom(&input); + if (s.ok()) { + result = handle.offset(); + } else { + // Strange: we can't decode the block handle in the index block. + // We'll just return the offset of the metaindex block, which is + // close to the whole file size for this case. + result = rep_->metaindex_handle.offset(); + } + } else { + // key is past the last key in the file. Approximate the offset + // by returning the offset of the metaindex block (which is + // right near the end of the file). + result = rep_->metaindex_handle.offset(); + } + delete index_iter; + return result; +} + +} // namespace leveldb diff --git a/src/leveldb/table/table_builder.cc b/src/leveldb/table/table_builder.cc new file mode 100644 index 0000000..62002c8 --- /dev/null +++ b/src/leveldb/table/table_builder.cc @@ -0,0 +1,270 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table_builder.h" + +#include +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block_builder.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +struct TableBuilder::Rep { + Options options; + Options index_block_options; + WritableFile* file; + uint64_t offset; + Status status; + BlockBuilder data_block; + BlockBuilder index_block; + std::string last_key; + int64_t num_entries; + bool closed; // Either Finish() or Abandon() has been called. + FilterBlockBuilder* filter_block; + + // We do not emit the index entry for a block until we have seen the + // first key for the next data block. This allows us to use shorter + // keys in the index block. For example, consider a block boundary + // between the keys "the quick brown fox" and "the who". We can use + // "the r" as the key for the index block entry since it is >= all + // entries in the first block and < all entries in subsequent + // blocks. + // + // Invariant: r->pending_index_entry is true only if data_block is empty. + bool pending_index_entry; + BlockHandle pending_handle; // Handle to add to index block + + std::string compressed_output; + + Rep(const Options& opt, WritableFile* f) + : options(opt), + index_block_options(opt), + file(f), + offset(0), + data_block(&options), + index_block(&index_block_options), + num_entries(0), + closed(false), + filter_block(opt.filter_policy == NULL ? NULL + : new FilterBlockBuilder(opt.filter_policy)), + pending_index_entry(false) { + index_block_options.block_restart_interval = 1; + } +}; + +TableBuilder::TableBuilder(const Options& options, WritableFile* file) + : rep_(new Rep(options, file)) { + if (rep_->filter_block != NULL) { + rep_->filter_block->StartBlock(0); + } +} + +TableBuilder::~TableBuilder() { + assert(rep_->closed); // Catch errors where caller forgot to call Finish() + delete rep_->filter_block; + delete rep_; +} + +Status TableBuilder::ChangeOptions(const Options& options) { + // Note: if more fields are added to Options, update + // this function to catch changes that should not be allowed to + // change in the middle of building a Table. + if (options.comparator != rep_->options.comparator) { + return Status::InvalidArgument("changing comparator while building table"); + } + + // Note that any live BlockBuilders point to rep_->options and therefore + // will automatically pick up the updated options. + rep_->options = options; + rep_->index_block_options = options; + rep_->index_block_options.block_restart_interval = 1; + return Status::OK(); +} + +void TableBuilder::Add(const Slice& key, const Slice& value) { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->num_entries > 0) { + assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); + } + + if (r->pending_index_entry) { + assert(r->data_block.empty()); + r->options.comparator->FindShortestSeparator(&r->last_key, key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + + if (r->filter_block != NULL) { + r->filter_block->AddKey(key); + } + + r->last_key.assign(key.data(), key.size()); + r->num_entries++; + r->data_block.Add(key, value); + + const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); + if (estimated_block_size >= r->options.block_size) { + Flush(); + } +} + +void TableBuilder::Flush() { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->data_block.empty()) return; + assert(!r->pending_index_entry); + WriteBlock(&r->data_block, &r->pending_handle); + if (ok()) { + r->pending_index_entry = true; + r->status = r->file->Flush(); + } + if (r->filter_block != NULL) { + r->filter_block->StartBlock(r->offset); + } +} + +void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { + // File format contains a sequence of blocks where each block has: + // block_data: uint8[n] + // type: uint8 + // crc: uint32 + assert(ok()); + Rep* r = rep_; + Slice raw = block->Finish(); + + Slice block_contents; + CompressionType type = r->options.compression; + // TODO(postrelease): Support more compression options: zlib? + switch (type) { + case kNoCompression: + block_contents = raw; + break; + + case kSnappyCompression: { + std::string* compressed = &r->compressed_output; + if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && + compressed->size() < raw.size() - (raw.size() / 8u)) { + block_contents = *compressed; + } else { + // Snappy not supported, or compressed less than 12.5%, so just + // store uncompressed form + block_contents = raw; + type = kNoCompression; + } + break; + } + } + WriteRawBlock(block_contents, type, handle); + r->compressed_output.clear(); + block->Reset(); +} + +void TableBuilder::WriteRawBlock(const Slice& block_contents, + CompressionType type, + BlockHandle* handle) { + Rep* r = rep_; + handle->set_offset(r->offset); + handle->set_size(block_contents.size()); + r->status = r->file->Append(block_contents); + if (r->status.ok()) { + char trailer[kBlockTrailerSize]; + trailer[0] = type; + uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); + crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type + EncodeFixed32(trailer+1, crc32c::Mask(crc)); + r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); + if (r->status.ok()) { + r->offset += block_contents.size() + kBlockTrailerSize; + } + } +} + +Status TableBuilder::status() const { + return rep_->status; +} + +Status TableBuilder::Finish() { + Rep* r = rep_; + Flush(); + assert(!r->closed); + r->closed = true; + + BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; + + // Write filter block + if (ok() && r->filter_block != NULL) { + WriteRawBlock(r->filter_block->Finish(), kNoCompression, + &filter_block_handle); + } + + // Write metaindex block + if (ok()) { + BlockBuilder meta_index_block(&r->options); + if (r->filter_block != NULL) { + // Add mapping from "filter.Name" to location of filter data + std::string key = "filter."; + key.append(r->options.filter_policy->Name()); + std::string handle_encoding; + filter_block_handle.EncodeTo(&handle_encoding); + meta_index_block.Add(key, handle_encoding); + } + + // TODO(postrelease): Add stats and other meta blocks + WriteBlock(&meta_index_block, &metaindex_block_handle); + } + + // Write index block + if (ok()) { + if (r->pending_index_entry) { + r->options.comparator->FindShortSuccessor(&r->last_key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + WriteBlock(&r->index_block, &index_block_handle); + } + + // Write footer + if (ok()) { + Footer footer; + footer.set_metaindex_handle(metaindex_block_handle); + footer.set_index_handle(index_block_handle); + std::string footer_encoding; + footer.EncodeTo(&footer_encoding); + r->status = r->file->Append(footer_encoding); + if (r->status.ok()) { + r->offset += footer_encoding.size(); + } + } + return r->status; +} + +void TableBuilder::Abandon() { + Rep* r = rep_; + assert(!r->closed); + r->closed = true; +} + +uint64_t TableBuilder::NumEntries() const { + return rep_->num_entries; +} + +uint64_t TableBuilder::FileSize() const { + return rep_->offset; +} + +} // namespace leveldb diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc new file mode 100644 index 0000000..c723bf8 --- /dev/null +++ b/src/leveldb/table/table_test.cc @@ -0,0 +1,868 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include +#include +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/table_builder.h" +#include "table/block.h" +#include "table/block_builder.h" +#include "table/format.h" +#include "util/random.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// Return reverse of "key". +// Used to test non-lexicographic comparators. +static std::string Reverse(const Slice& key) { + std::string str(key.ToString()); + std::string rev(""); + for (std::string::reverse_iterator rit = str.rbegin(); + rit != str.rend(); ++rit) { + rev.push_back(*rit); + } + return rev; +} + +namespace { +class ReverseKeyComparator : public Comparator { + public: + virtual const char* Name() const { + return "leveldb.ReverseBytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(Reverse(a), Reverse(b)); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + std::string s = Reverse(*start); + std::string l = Reverse(limit); + BytewiseComparator()->FindShortestSeparator(&s, l); + *start = Reverse(s); + } + + virtual void FindShortSuccessor(std::string* key) const { + std::string s = Reverse(*key); + BytewiseComparator()->FindShortSuccessor(&s); + *key = Reverse(s); + } +}; +} // namespace +static ReverseKeyComparator reverse_key_comparator; + +static void Increment(const Comparator* cmp, std::string* key) { + if (cmp == BytewiseComparator()) { + key->push_back('\0'); + } else { + assert(cmp == &reverse_key_comparator); + std::string rev = Reverse(*key); + rev.push_back('\0'); + *key = Reverse(rev); + } +} + +// An STL comparator that uses a Comparator +namespace { +struct STLLessThan { + const Comparator* cmp; + + STLLessThan() : cmp(BytewiseComparator()) { } + STLLessThan(const Comparator* c) : cmp(c) { } + bool operator()(const std::string& a, const std::string& b) const { + return cmp->Compare(Slice(a), Slice(b)) < 0; + } +}; +} // namespace + +class StringSink: public WritableFile { + public: + ~StringSink() { } + + const std::string& contents() const { return contents_; } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + virtual Status Append(const Slice& data) { + contents_.append(data.data(), data.size()); + return Status::OK(); + } + + private: + std::string contents_; +}; + + +class StringSource: public RandomAccessFile { + public: + StringSource(const Slice& contents) + : contents_(contents.data(), contents.size()) { + } + + virtual ~StringSource() { } + + uint64_t Size() const { return contents_.size(); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + if (offset > contents_.size()) { + return Status::InvalidArgument("invalid Read offset"); + } + if (offset + n > contents_.size()) { + n = contents_.size() - offset; + } + memcpy(scratch, &contents_[offset], n); + *result = Slice(scratch, n); + return Status::OK(); + } + + private: + std::string contents_; +}; + +typedef std::map KVMap; + +// Helper class for tests to unify the interface between +// BlockBuilder/TableBuilder and Block/Table. +class Constructor { + public: + explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { } + virtual ~Constructor() { } + + void Add(const std::string& key, const Slice& value) { + data_[key] = value.ToString(); + } + + // Finish constructing the data structure with all the keys that have + // been added so far. Returns the keys in sorted order in "*keys" + // and stores the key/value pairs in "*kvmap" + void Finish(const Options& options, + std::vector* keys, + KVMap* kvmap) { + *kvmap = data_; + keys->clear(); + for (KVMap::const_iterator it = data_.begin(); + it != data_.end(); + ++it) { + keys->push_back(it->first); + } + data_.clear(); + Status s = FinishImpl(options, *kvmap); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + // Construct the data structure from the data in "data" + virtual Status FinishImpl(const Options& options, const KVMap& data) = 0; + + virtual Iterator* NewIterator() const = 0; + + virtual const KVMap& data() { return data_; } + + virtual DB* db() const { return NULL; } // Overridden in DBConstructor + + private: + KVMap data_; +}; + +class BlockConstructor: public Constructor { + public: + explicit BlockConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp), + block_(NULL) { } + ~BlockConstructor() { + delete block_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete block_; + block_ = NULL; + BlockBuilder builder(&options); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + } + // Open the block + data_ = builder.Finish().ToString(); + BlockContents contents; + contents.data = data_; + contents.cachable = false; + contents.heap_allocated = false; + block_ = new Block(contents); + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return block_->NewIterator(comparator_); + } + + private: + const Comparator* comparator_; + std::string data_; + Block* block_; + + BlockConstructor(); +}; + +class TableConstructor: public Constructor { + public: + TableConstructor(const Comparator* cmp) + : Constructor(cmp), + source_(NULL), table_(NULL) { + } + ~TableConstructor() { + Reset(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + Reset(); + StringSink sink; + TableBuilder builder(options, &sink); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + ASSERT_TRUE(builder.status().ok()); + } + Status s = builder.Finish(); + ASSERT_TRUE(s.ok()) << s.ToString(); + + ASSERT_EQ(sink.contents().size(), builder.FileSize()); + + // Open the table + source_ = new StringSource(sink.contents()); + Options table_options; + table_options.comparator = options.comparator; + return Table::Open(table_options, source_, sink.contents().size(), &table_); + } + + virtual Iterator* NewIterator() const { + return table_->NewIterator(ReadOptions()); + } + + uint64_t ApproximateOffsetOf(const Slice& key) const { + return table_->ApproximateOffsetOf(key); + } + + private: + void Reset() { + delete table_; + delete source_; + table_ = NULL; + source_ = NULL; + } + + StringSource* source_; + Table* table_; + + TableConstructor(); +}; + +// A helper class that converts internal format keys into user keys +class KeyConvertingIterator: public Iterator { + public: + explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { } + virtual ~KeyConvertingIterator() { delete iter_; } + virtual bool Valid() const { return iter_->Valid(); } + virtual void Seek(const Slice& target) { + ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue); + std::string encoded; + AppendInternalKey(&encoded, ikey); + iter_->Seek(encoded); + } + virtual void SeekToFirst() { iter_->SeekToFirst(); } + virtual void SeekToLast() { iter_->SeekToLast(); } + virtual void Next() { iter_->Next(); } + virtual void Prev() { iter_->Prev(); } + + virtual Slice key() const { + assert(Valid()); + ParsedInternalKey key; + if (!ParseInternalKey(iter_->key(), &key)) { + status_ = Status::Corruption("malformed internal key"); + return Slice("corrupted key"); + } + return key.user_key; + } + + virtual Slice value() const { return iter_->value(); } + virtual Status status() const { + return status_.ok() ? iter_->status() : status_; + } + + private: + mutable Status status_; + Iterator* iter_; + + // No copying allowed + KeyConvertingIterator(const KeyConvertingIterator&); + void operator=(const KeyConvertingIterator&); +}; + +class MemTableConstructor: public Constructor { + public: + explicit MemTableConstructor(const Comparator* cmp) + : Constructor(cmp), + internal_comparator_(cmp) { + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + } + ~MemTableConstructor() { + memtable_->Unref(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + memtable_->Unref(); + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + int seq = 1; + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + memtable_->Add(seq, kTypeValue, it->first, it->second); + seq++; + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return new KeyConvertingIterator(memtable_->NewIterator()); + } + + private: + InternalKeyComparator internal_comparator_; + MemTable* memtable_; +}; + +class DBConstructor: public Constructor { + public: + explicit DBConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp) { + db_ = NULL; + NewDB(); + } + ~DBConstructor() { + delete db_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete db_; + db_ = NULL; + NewDB(); + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + WriteBatch batch; + batch.Put(it->first, it->second); + ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok()); + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return db_->NewIterator(ReadOptions()); + } + + virtual DB* db() const { return db_; } + + private: + void NewDB() { + std::string name = test::TmpDir() + "/table_testdb"; + + Options options; + options.comparator = comparator_; + Status status = DestroyDB(name, options); + ASSERT_TRUE(status.ok()) << status.ToString(); + + options.create_if_missing = true; + options.error_if_exists = true; + options.write_buffer_size = 10000; // Something small to force merging + status = DB::Open(options, name, &db_); + ASSERT_TRUE(status.ok()) << status.ToString(); + } + + const Comparator* comparator_; + DB* db_; +}; + +enum TestType { + TABLE_TEST, + BLOCK_TEST, + MEMTABLE_TEST, + DB_TEST +}; + +struct TestArgs { + TestType type; + bool reverse_compare; + int restart_interval; +}; + +static const TestArgs kTestArgList[] = { + { TABLE_TEST, false, 16 }, + { TABLE_TEST, false, 1 }, + { TABLE_TEST, false, 1024 }, + { TABLE_TEST, true, 16 }, + { TABLE_TEST, true, 1 }, + { TABLE_TEST, true, 1024 }, + + { BLOCK_TEST, false, 16 }, + { BLOCK_TEST, false, 1 }, + { BLOCK_TEST, false, 1024 }, + { BLOCK_TEST, true, 16 }, + { BLOCK_TEST, true, 1 }, + { BLOCK_TEST, true, 1024 }, + + // Restart interval does not matter for memtables + { MEMTABLE_TEST, false, 16 }, + { MEMTABLE_TEST, true, 16 }, + + // Do not bother with restart interval variations for DB + { DB_TEST, false, 16 }, + { DB_TEST, true, 16 }, +}; +static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]); + +class Harness { + public: + Harness() : constructor_(NULL) { } + + void Init(const TestArgs& args) { + delete constructor_; + constructor_ = NULL; + options_ = Options(); + + options_.block_restart_interval = args.restart_interval; + // Use shorter block size for tests to exercise block boundary + // conditions more. + options_.block_size = 256; + if (args.reverse_compare) { + options_.comparator = &reverse_key_comparator; + } + switch (args.type) { + case TABLE_TEST: + constructor_ = new TableConstructor(options_.comparator); + break; + case BLOCK_TEST: + constructor_ = new BlockConstructor(options_.comparator); + break; + case MEMTABLE_TEST: + constructor_ = new MemTableConstructor(options_.comparator); + break; + case DB_TEST: + constructor_ = new DBConstructor(options_.comparator); + break; + } + } + + ~Harness() { + delete constructor_; + } + + void Add(const std::string& key, const std::string& value) { + constructor_->Add(key, value); + } + + void Test(Random* rnd) { + std::vector keys; + KVMap data; + constructor_->Finish(options_, &keys, &data); + + TestForwardScan(keys, data); + TestBackwardScan(keys, data); + TestRandomAccess(rnd, keys, data); + } + + void TestForwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToFirst(); + for (KVMap::const_iterator model_iter = data.begin(); + model_iter != data.end(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Next(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestBackwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + for (KVMap::const_reverse_iterator model_iter = data.rbegin(); + model_iter != data.rend(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Prev(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestRandomAccess(Random* rnd, + const std::vector& keys, + const KVMap& data) { + static const bool kVerbose = false; + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + KVMap::const_iterator model_iter = data.begin(); + if (kVerbose) fprintf(stderr, "---\n"); + for (int i = 0; i < 200; i++) { + const int toss = rnd->Uniform(5); + switch (toss) { + case 0: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Next\n"); + iter->Next(); + ++model_iter; + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 1: { + if (kVerbose) fprintf(stderr, "SeekToFirst\n"); + iter->SeekToFirst(); + model_iter = data.begin(); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 2: { + std::string key = PickRandomKey(rnd, keys); + model_iter = data.lower_bound(key); + if (kVerbose) fprintf(stderr, "Seek '%s'\n", + EscapeString(key).c_str()); + iter->Seek(Slice(key)); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 3: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Prev\n"); + iter->Prev(); + if (model_iter == data.begin()) { + model_iter = data.end(); // Wrap around to invalid value + } else { + --model_iter; + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 4: { + if (kVerbose) fprintf(stderr, "SeekToLast\n"); + iter->SeekToLast(); + if (keys.empty()) { + model_iter = data.end(); + } else { + std::string last = data.rbegin()->first; + model_iter = data.lower_bound(last); + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + } + } + delete iter; + } + + std::string ToString(const KVMap& data, const KVMap::const_iterator& it) { + if (it == data.end()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const KVMap& data, + const KVMap::const_reverse_iterator& it) { + if (it == data.rend()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const Iterator* it) { + if (!it->Valid()) { + return "END"; + } else { + return "'" + it->key().ToString() + "->" + it->value().ToString() + "'"; + } + } + + std::string PickRandomKey(Random* rnd, const std::vector& keys) { + if (keys.empty()) { + return "foo"; + } else { + const int index = rnd->Uniform(keys.size()); + std::string result = keys[index]; + switch (rnd->Uniform(3)) { + case 0: + // Return an existing key + break; + case 1: { + // Attempt to return something smaller than an existing key + if (result.size() > 0 && result[result.size()-1] > '\0') { + result[result.size()-1]--; + } + break; + } + case 2: { + // Return something larger than an existing key + Increment(options_.comparator, &result); + break; + } + } + return result; + } + } + + // Returns NULL if not running against a DB + DB* db() const { return constructor_->db(); } + + private: + Options options_; + Constructor* constructor_; +}; + +// Test empty table/block. +TEST(Harness, Empty) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Test(&rnd); + } +} + +// Special test for a block with no restart entries. The C++ leveldb +// code never generates such blocks, but the Java version of leveldb +// seems to. +TEST(Harness, ZeroRestartPointsInBlock) { + char data[sizeof(uint32_t)]; + memset(data, 0, sizeof(data)); + BlockContents contents; + contents.data = Slice(data, sizeof(data)); + contents.cachable = false; + contents.heap_allocated = false; + Block block(contents); + Iterator* iter = block.NewIterator(BytewiseComparator()); + iter->SeekToFirst(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + ASSERT_TRUE(!iter->Valid()); + iter->Seek("foo"); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +// Test the empty key +TEST(Harness, SimpleEmptyKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Add("", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSingle) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 2); + Add("abc", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleMulti) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 3); + Add("abc", "v"); + Add("abcd", "v"); + Add("ac", "v2"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSpecialKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 4); + Add("\xff\xff", "v3"); + Test(&rnd); + } +} + +TEST(Harness, Randomized) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 5); + for (int num_entries = 0; num_entries < 2000; + num_entries += (num_entries < 50 ? 1 : 200)) { + if ((num_entries % 10) == 0) { + fprintf(stderr, "case %d of %d: num_entries = %d\n", + (i + 1), int(kNumTestArgs), num_entries); + } + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + } + } +} + +TEST(Harness, RandomizedLongDB) { + Random rnd(test::RandomSeed()); + TestArgs args = { DB_TEST, false, 16 }; + Init(args); + int num_entries = 100000; + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + + // We must have created enough data to force merging + int files = 0; + for (int level = 0; level < config::kNumLevels; level++) { + std::string value; + char name[100]; + snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level); + ASSERT_TRUE(db()->GetProperty(name, &value)); + files += atoi(value.c_str()); + } + ASSERT_GT(files, 0); +} + +class MemTableTest { }; + +TEST(MemTableTest, Simple) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* memtable = new MemTable(cmp); + memtable->Ref(); + WriteBatch batch; + WriteBatchInternal::SetSequence(&batch, 100); + batch.Put(std::string("k1"), std::string("v1")); + batch.Put(std::string("k2"), std::string("v2")); + batch.Put(std::string("k3"), std::string("v3")); + batch.Put(std::string("largekey"), std::string("vlarge")); + ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok()); + + Iterator* iter = memtable->NewIterator(); + iter->SeekToFirst(); + while (iter->Valid()) { + fprintf(stderr, "key: '%s' -> '%s'\n", + iter->key().ToString().c_str(), + iter->value().ToString().c_str()); + iter->Next(); + } + + delete iter; + memtable->Unref(); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +class TableTest { }; + +TEST(TableTest, ApproximateOffsetOfPlain) { + TableConstructor c(BytewiseComparator()); + c.Add("k01", "hello"); + c.Add("k02", "hello2"); + c.Add("k03", std::string(10000, 'x')); + c.Add("k04", std::string(200000, 'x')); + c.Add("k05", std::string(300000, 'x')); + c.Add("k06", "hello3"); + c.Add("k07", std::string(100000, 'x')); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kNoCompression; + 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("k01a"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000)); + +} + +static bool SnappyCompressionSupported() { + std::string out; + Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + return port::Snappy_Compress(in.data(), in.size(), &out); +} + +TEST(TableTest, ApproximateOffsetOfCompressed) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + + Random rnd(301); + TableConstructor c(BytewiseComparator()); + std::string tmp; + c.Add("k01", "hello"); + c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + c.Add("k03", "hello3"); + c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + 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)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/table/two_level_iterator.cc b/src/leveldb/table/two_level_iterator.cc new file mode 100644 index 0000000..7822eba --- /dev/null +++ b/src/leveldb/table/two_level_iterator.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/two_level_iterator.h" + +#include "leveldb/table.h" +#include "table/block.h" +#include "table/format.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { + +typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); + +class TwoLevelIterator: public Iterator { + public: + TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options); + + virtual ~TwoLevelIterator(); + + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + virtual void Next(); + virtual void Prev(); + + virtual bool Valid() const { + return data_iter_.Valid(); + } + virtual Slice key() const { + assert(Valid()); + return data_iter_.key(); + } + virtual Slice value() const { + assert(Valid()); + return data_iter_.value(); + } + virtual Status status() const { + // It'd be nice if status() returned a const Status& instead of a Status + if (!index_iter_.status().ok()) { + return index_iter_.status(); + } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) { + return data_iter_.status(); + } else { + return status_; + } + } + + private: + void SaveError(const Status& s) { + if (status_.ok() && !s.ok()) status_ = s; + } + void SkipEmptyDataBlocksForward(); + void SkipEmptyDataBlocksBackward(); + void SetDataIterator(Iterator* data_iter); + void InitDataBlock(); + + BlockFunction block_function_; + void* arg_; + const ReadOptions options_; + Status status_; + IteratorWrapper index_iter_; + IteratorWrapper data_iter_; // May be NULL + // If data_iter_ is non-NULL, then "data_block_handle_" holds the + // "index_value" passed to block_function_ to create the data_iter_. + std::string data_block_handle_; +}; + +TwoLevelIterator::TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) + : block_function_(block_function), + arg_(arg), + options_(options), + index_iter_(index_iter), + data_iter_(NULL) { +} + +TwoLevelIterator::~TwoLevelIterator() { +} + +void TwoLevelIterator::Seek(const Slice& target) { + index_iter_.Seek(target); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.Seek(target); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToFirst() { + index_iter_.SeekToFirst(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToLast() { + index_iter_.SeekToLast(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + SkipEmptyDataBlocksBackward(); +} + +void TwoLevelIterator::Next() { + assert(Valid()); + data_iter_.Next(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::Prev() { + assert(Valid()); + data_iter_.Prev(); + SkipEmptyDataBlocksBackward(); +} + + +void TwoLevelIterator::SkipEmptyDataBlocksForward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Next(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + } +} + +void TwoLevelIterator::SkipEmptyDataBlocksBackward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Prev(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + } +} + +void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { + if (data_iter_.iter() != NULL) SaveError(data_iter_.status()); + data_iter_.Set(data_iter); +} + +void TwoLevelIterator::InitDataBlock() { + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + } else { + Slice handle = index_iter_.value(); + if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) { + // data_iter_ is already constructed with this iterator, so + // no need to change anything + } else { + Iterator* iter = (*block_function_)(arg_, options_, handle); + data_block_handle_.assign(handle.data(), handle.size()); + SetDataIterator(iter); + } + } +} + +} // namespace + +Iterator* NewTwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) { + return new TwoLevelIterator(index_iter, block_function, arg, options); +} + +} // namespace leveldb diff --git a/src/leveldb/table/two_level_iterator.h b/src/leveldb/table/two_level_iterator.h new file mode 100644 index 0000000..629ca34 --- /dev/null +++ b/src/leveldb/table/two_level_iterator.h @@ -0,0 +1,34 @@ +// 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_TABLE_TWO_LEVEL_ITERATOR_H_ +#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ + +#include "leveldb/iterator.h" + +namespace leveldb { + +struct ReadOptions; + +// Return a new two level iterator. A two-level iterator contains an +// index iterator whose values point to a sequence of blocks where +// each block is itself a sequence of key,value pairs. The returned +// two-level iterator yields the concatenation of all key/value pairs +// in the sequence of blocks. Takes ownership of "index_iter" and +// will delete it when no longer needed. +// +// Uses a supplied function to convert an index_iter value into +// an iterator over the contents of the corresponding block. +extern Iterator* NewTwoLevelIterator( + Iterator* index_iter, + Iterator* (*block_function)( + void* arg, + const ReadOptions& options, + const Slice& index_value), + void* arg, + const ReadOptions& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/src/leveldb/util/arena.cc b/src/leveldb/util/arena.cc new file mode 100644 index 0000000..9551d6a --- /dev/null +++ b/src/leveldb/util/arena.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" +#include + +namespace leveldb { + +static const int kBlockSize = 4096; + +Arena::Arena() { + blocks_memory_ = 0; + alloc_ptr_ = NULL; // First allocation will allocate a block + alloc_bytes_remaining_ = 0; +} + +Arena::~Arena() { + for (size_t i = 0; i < blocks_.size(); i++) { + delete[] blocks_[i]; + } +} + +char* Arena::AllocateFallback(size_t bytes) { + if (bytes > kBlockSize / 4) { + // Object is more than a quarter of our block size. Allocate it separately + // to avoid wasting too much space in leftover bytes. + char* result = AllocateNewBlock(bytes); + return result; + } + + // We waste the remaining space in the current block. + alloc_ptr_ = AllocateNewBlock(kBlockSize); + alloc_bytes_remaining_ = kBlockSize; + + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; +} + +char* Arena::AllocateAligned(size_t bytes) { + const int align = sizeof(void*); // We'll align to pointer size + assert((align & (align-1)) == 0); // Pointer size should be a power of 2 + size_t current_mod = reinterpret_cast(alloc_ptr_) & (align-1); + size_t slop = (current_mod == 0 ? 0 : align - current_mod); + size_t needed = bytes + slop; + char* result; + if (needed <= alloc_bytes_remaining_) { + result = alloc_ptr_ + slop; + alloc_ptr_ += needed; + alloc_bytes_remaining_ -= needed; + } else { + // AllocateFallback always returned aligned memory + result = AllocateFallback(bytes); + } + assert((reinterpret_cast(result) & (align-1)) == 0); + return result; +} + +char* Arena::AllocateNewBlock(size_t block_bytes) { + char* result = new char[block_bytes]; + blocks_memory_ += block_bytes; + blocks_.push_back(result); + return result; +} + +} // namespace leveldb diff --git a/src/leveldb/util/arena.h b/src/leveldb/util/arena.h new file mode 100644 index 0000000..8f7dde2 --- /dev/null +++ b/src/leveldb/util/arena.h @@ -0,0 +1,68 @@ +// 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_UTIL_ARENA_H_ +#define STORAGE_LEVELDB_UTIL_ARENA_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Arena { + public: + Arena(); + ~Arena(); + + // Return a pointer to a newly allocated memory block of "bytes" bytes. + char* Allocate(size_t bytes); + + // Allocate memory with the normal alignment guarantees provided by malloc + 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). + size_t MemoryUsage() const { + return blocks_memory_ + blocks_.capacity() * sizeof(char*); + } + + private: + char* AllocateFallback(size_t bytes); + char* AllocateNewBlock(size_t block_bytes); + + // Allocation state + char* alloc_ptr_; + size_t alloc_bytes_remaining_; + + // Array of new[] allocated memory blocks + std::vector blocks_; + + // Bytes of memory in blocks allocated so far + size_t blocks_memory_; + + // No copying allowed + Arena(const Arena&); + void operator=(const Arena&); +}; + +inline char* Arena::Allocate(size_t bytes) { + // The semantics of what to return are a bit messy if we allow + // 0-byte allocations, so we disallow them here (we don't need + // them for our internal use). + assert(bytes > 0); + if (bytes <= alloc_bytes_remaining_) { + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; + } + return AllocateFallback(bytes); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/src/leveldb/util/arena_test.cc b/src/leveldb/util/arena_test.cc new file mode 100644 index 0000000..63d1778 --- /dev/null +++ b/src/leveldb/util/arena_test.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" + +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +class ArenaTest { }; + +TEST(ArenaTest, Empty) { + Arena arena; +} + +TEST(ArenaTest, Simple) { + std::vector > allocated; + Arena arena; + const int N = 100000; + size_t bytes = 0; + Random rnd(301); + for (int i = 0; i < N; i++) { + size_t s; + if (i % (N / 10) == 0) { + s = i; + } else { + s = rnd.OneIn(4000) ? rnd.Uniform(6000) : + (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20)); + } + if (s == 0) { + // Our arena disallows size 0 allocations. + s = 1; + } + char* r; + if (rnd.OneIn(10)) { + r = arena.AllocateAligned(s); + } else { + r = arena.Allocate(s); + } + + for (int b = 0; b < s; b++) { + // Fill the "i"th allocation with a known bit pattern + r[b] = i % 256; + } + bytes += s; + allocated.push_back(std::make_pair(s, r)); + ASSERT_GE(arena.MemoryUsage(), bytes); + if (i > N/10) { + ASSERT_LE(arena.MemoryUsage(), bytes * 1.10); + } + } + for (int i = 0; i < allocated.size(); i++) { + size_t num_bytes = allocated[i].first; + const char* p = allocated[i].second; + for (int b = 0; b < num_bytes; b++) { + // Check the "i"th allocation for the known bit pattern + ASSERT_EQ(int(p[b]) & 0xff, i % 256); + } + } +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc new file mode 100644 index 0000000..d7941cd --- /dev/null +++ b/src/leveldb/util/bloom.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +namespace { +static uint32_t BloomHash(const Slice& key) { + return Hash(key.data(), key.size(), 0xbc9f1d34); +} + +class BloomFilterPolicy : public FilterPolicy { + private: + size_t bits_per_key_; + size_t k_; + + public: + explicit BloomFilterPolicy(int bits_per_key) + : bits_per_key_(bits_per_key) { + // We intentionally round down to reduce probing cost a little bit + k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) + if (k_ < 1) k_ = 1; + if (k_ > 30) k_ = 30; + } + + virtual const char* Name() const { + return "leveldb.BuiltinBloomFilter"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Compute bloom filter size (in both bits and bytes) + size_t bits = n * bits_per_key_; + + // For small n, we can see a very high false positive rate. Fix it + // by enforcing a minimum bloom filter length. + if (bits < 64) bits = 64; + + size_t bytes = (bits + 7) / 8; + bits = bytes * 8; + + const size_t init_size = dst->size(); + dst->resize(init_size + bytes, 0); + dst->push_back(static_cast(k_)); // Remember # of probes in filter + char* array = &(*dst)[init_size]; + for (size_t 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]); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k_; j++) { + const uint32_t bitpos = h % bits; + array[bitpos/8] |= (1 << (bitpos % 8)); + h += delta; + } + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { + const size_t len = bloom_filter.size(); + if (len < 2) return false; + + const char* array = bloom_filter.data(); + const size_t bits = (len - 1) * 8; + + // Use the encoded k so that we can read filters generated by + // bloom filters created using different parameters. + const size_t k = array[len-1]; + if (k > 30) { + // Reserved for potentially new encodings for short bloom filters. + // Consider it a match. + return true; + } + + uint32_t h = BloomHash(key); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k; j++) { + const uint32_t bitpos = h % bits; + if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false; + h += delta; + } + return true; + } +}; +} + +const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { + return new BloomFilterPolicy(bits_per_key); +} + +} // namespace leveldb diff --git a/src/leveldb/util/bloom_test.cc b/src/leveldb/util/bloom_test.cc new file mode 100644 index 0000000..0bf8e8d --- /dev/null +++ b/src/leveldb/util/bloom_test.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "util/coding.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kVerbose = 1; + +static Slice Key(int i, char* buffer) { + EncodeFixed32(buffer, i); + return Slice(buffer, sizeof(uint32_t)); +} + +class BloomTest { + private: + const FilterPolicy* policy_; + std::string filter_; + std::vector keys_; + + public: + BloomTest() : policy_(NewBloomFilterPolicy(10)) { } + + ~BloomTest() { + delete policy_; + } + + void Reset() { + keys_.clear(); + filter_.clear(); + } + + void Add(const Slice& s) { + keys_.push_back(s.ToString()); + } + + void Build() { + std::vector key_slices; + for (size_t i = 0; i < keys_.size(); i++) { + key_slices.push_back(Slice(keys_[i])); + } + filter_.clear(); + policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_); + keys_.clear(); + if (kVerbose >= 2) DumpFilter(); + } + + size_t FilterSize() const { + return filter_.size(); + } + + void DumpFilter() { + fprintf(stderr, "F("); + for (size_t i = 0; i+1 < filter_.size(); i++) { + const unsigned int c = static_cast(filter_[i]); + for (int j = 0; j < 8; j++) { + fprintf(stderr, "%c", (c & (1 <KeyMayMatch(s, filter_); + } + + double FalsePositiveRate() { + char buffer[sizeof(int)]; + int result = 0; + for (int i = 0; i < 10000; i++) { + if (Matches(Key(i + 1000000000, buffer))) { + result++; + } + } + return result / 10000.0; + } +}; + +TEST(BloomTest, EmptyFilter) { + ASSERT_TRUE(! Matches("hello")); + ASSERT_TRUE(! Matches("world")); +} + +TEST(BloomTest, Small) { + Add("hello"); + Add("world"); + ASSERT_TRUE(Matches("hello")); + ASSERT_TRUE(Matches("world")); + ASSERT_TRUE(! Matches("x")); + ASSERT_TRUE(! Matches("foo")); +} + +static int NextLength(int length) { + if (length < 10) { + length += 1; + } else if (length < 100) { + length += 10; + } else if (length < 1000) { + length += 100; + } else { + length += 1000; + } + return length; +} + +TEST(BloomTest, VaryingLengths) { + char buffer[sizeof(int)]; + + // Count number of filters that significantly exceed the false positive rate + int mediocre_filters = 0; + int good_filters = 0; + + for (int length = 1; length <= 10000; length = NextLength(length)) { + Reset(); + for (int i = 0; i < length; i++) { + Add(Key(i, buffer)); + } + Build(); + + ASSERT_LE(FilterSize(), (length * 10 / 8) + 40) << length; + + // All added keys must match + for (int i = 0; i < length; i++) { + ASSERT_TRUE(Matches(Key(i, buffer))) + << "Length " << length << "; key " << i; + } + + // Check false positive rate + double rate = FalsePositiveRate(); + if (kVerbose >= 1) { + fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", + rate*100.0, length, static_cast(FilterSize())); + } + ASSERT_LE(rate, 0.02); // Must not be over 2% + if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often + else good_filters++; + } + if (kVerbose >= 1) { + fprintf(stderr, "Filters: %d good, %d mediocre\n", + good_filters, mediocre_filters); + } + ASSERT_LE(mediocre_filters, good_filters/5); +} + +// Different bits-per-byte + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc new file mode 100644 index 0000000..8b197bc --- /dev/null +++ b/src/leveldb/util/cache.cc @@ -0,0 +1,325 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include + +#include "leveldb/cache.h" +#include "port/port.h" +#include "util/hash.h" +#include "util/mutexlock.h" + +namespace leveldb { + +Cache::~Cache() { +} + +namespace { + +// LRU cache implementation + +// An entry is a variable length heap-allocated structure. Entries +// are kept in a circular doubly linked list ordered by access time. +struct LRUHandle { + void* value; + void (*deleter)(const Slice&, void* value); + LRUHandle* next_hash; + LRUHandle* next; + LRUHandle* prev; + size_t charge; // TODO(opt): Only allow uint32_t? + size_t key_length; + uint32_t refs; + uint32_t hash; // Hash of key(); used for fast sharding and comparisons + char key_data[1]; // Beginning of key + + Slice key() const { + // For cheaper lookups, we allow a temporary Handle object + // to store a pointer to a key in "value". + if (next == this) { + return *(reinterpret_cast(value)); + } else { + return Slice(key_data, key_length); + } + } +}; + +// We provide our own simple hash table since it removes a whole bunch +// of porting hacks and is also faster than some of the built-in hash +// table implementations in some of the compiler/runtime combinations +// we have tested. E.g., readrandom speeds up by ~5% over the g++ +// 4.4.3's builtin hashtable. +class HandleTable { + public: + HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); } + ~HandleTable() { delete[] list_; } + + LRUHandle* Lookup(const Slice& key, uint32_t hash) { + return *FindPointer(key, hash); + } + + LRUHandle* Insert(LRUHandle* h) { + LRUHandle** ptr = FindPointer(h->key(), h->hash); + LRUHandle* old = *ptr; + h->next_hash = (old == NULL ? NULL : old->next_hash); + *ptr = h; + if (old == NULL) { + ++elems_; + if (elems_ > length_) { + // Since each cache entry is fairly large, we aim for a small + // average linked list length (<= 1). + Resize(); + } + } + return old; + } + + LRUHandle* Remove(const Slice& key, uint32_t hash) { + LRUHandle** ptr = FindPointer(key, hash); + LRUHandle* result = *ptr; + if (result != NULL) { + *ptr = result->next_hash; + --elems_; + } + return result; + } + + private: + // The table consists of an array of buckets where each bucket is + // a linked list of cache entries that hash into the bucket. + uint32_t length_; + uint32_t elems_; + LRUHandle** list_; + + // Return a pointer to slot that points to a cache entry that + // matches key/hash. If there is no such cache entry, return a + // pointer to the trailing slot in the corresponding linked list. + LRUHandle** FindPointer(const Slice& key, uint32_t hash) { + LRUHandle** ptr = &list_[hash & (length_ - 1)]; + while (*ptr != NULL && + ((*ptr)->hash != hash || key != (*ptr)->key())) { + ptr = &(*ptr)->next_hash; + } + return ptr; + } + + void Resize() { + uint32_t new_length = 4; + while (new_length < elems_) { + new_length *= 2; + } + LRUHandle** new_list = new LRUHandle*[new_length]; + memset(new_list, 0, sizeof(new_list[0]) * new_length); + uint32_t count = 0; + for (uint32_t i = 0; i < length_; i++) { + LRUHandle* h = list_[i]; + while (h != NULL) { + LRUHandle* next = h->next_hash; + uint32_t hash = h->hash; + LRUHandle** ptr = &new_list[hash & (new_length - 1)]; + h->next_hash = *ptr; + *ptr = h; + h = next; + count++; + } + } + assert(elems_ == count); + delete[] list_; + list_ = new_list; + length_ = new_length; + } +}; + +// A single shard of sharded cache. +class LRUCache { + public: + LRUCache(); + ~LRUCache(); + + // Separate from constructor so caller can easily make an array of LRUCache + void SetCapacity(size_t capacity) { capacity_ = capacity; } + + // Like Cache methods, but with an extra "hash" parameter. + Cache::Handle* Insert(const Slice& key, uint32_t hash, + void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)); + Cache::Handle* Lookup(const Slice& key, uint32_t hash); + void Release(Cache::Handle* handle); + void Erase(const Slice& key, uint32_t hash); + + private: + void LRU_Remove(LRUHandle* e); + void LRU_Append(LRUHandle* e); + void Unref(LRUHandle* e); + + // Initialized before use. + size_t capacity_; + + // mutex_ protects the following state. + port::Mutex mutex_; + size_t usage_; + + // Dummy head of LRU list. + // lru.prev is newest entry, lru.next is oldest entry. + LRUHandle lru_; + + HandleTable table_; +}; + +LRUCache::LRUCache() + : usage_(0) { + // Make empty circular linked list + lru_.next = &lru_; + lru_.prev = &lru_; +} + +LRUCache::~LRUCache() { + for (LRUHandle* e = lru_.next; e != &lru_; ) { + LRUHandle* next = e->next; + assert(e->refs == 1); // Error if caller has an unreleased handle + Unref(e); + e = next; + } +} + +void LRUCache::Unref(LRUHandle* e) { + assert(e->refs > 0); + e->refs--; + if (e->refs <= 0) { + usage_ -= e->charge; + (*e->deleter)(e->key(), e->value); + free(e); + } +} + +void LRUCache::LRU_Remove(LRUHandle* e) { + e->next->prev = e->prev; + 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; + e->prev->next = e; + e->next->prev = e; +} + +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); + } + return reinterpret_cast(e); +} + +void LRUCache::Release(Cache::Handle* handle) { + MutexLock l(&mutex_); + Unref(reinterpret_cast(handle)); +} + +Cache::Handle* LRUCache::Insert( + const Slice& key, uint32_t hash, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + MutexLock l(&mutex_); + + LRUHandle* e = reinterpret_cast( + malloc(sizeof(LRUHandle)-1 + key.size())); + e->value = value; + e->deleter = deleter; + e->charge = charge; + e->key_length = key.size(); + e->hash = hash; + e->refs = 2; // One from LRUCache, one 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); + } + + while (usage_ > capacity_ && lru_.next != &lru_) { + LRUHandle* old = lru_.next; + LRU_Remove(old); + table_.Remove(old->key(), old->hash); + Unref(old); + } + + return reinterpret_cast(e); +} + +void LRUCache::Erase(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Remove(key, hash); + if (e != NULL) { + LRU_Remove(e); + Unref(e); + } +} + +static const int kNumShardBits = 4; +static const int kNumShards = 1 << kNumShardBits; + +class ShardedLRUCache : public Cache { + private: + LRUCache shard_[kNumShards]; + port::Mutex id_mutex_; + uint64_t last_id_; + + static inline uint32_t HashSlice(const Slice& s) { + return Hash(s.data(), s.size(), 0); + } + + static uint32_t Shard(uint32_t hash) { + return hash >> (32 - kNumShardBits); + } + + public: + explicit ShardedLRUCache(size_t capacity) + : last_id_(0) { + const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; + for (int s = 0; s < kNumShards; s++) { + shard_[s].SetCapacity(per_shard); + } + } + virtual ~ShardedLRUCache() { } + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); + } + virtual Handle* Lookup(const Slice& key) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Lookup(key, hash); + } + virtual void Release(Handle* handle) { + LRUHandle* h = reinterpret_cast(handle); + shard_[Shard(h->hash)].Release(handle); + } + virtual void Erase(const Slice& key) { + const uint32_t hash = HashSlice(key); + shard_[Shard(hash)].Erase(key, hash); + } + virtual void* Value(Handle* handle) { + return reinterpret_cast(handle)->value; + } + virtual uint64_t NewId() { + MutexLock l(&id_mutex_); + return ++(last_id_); + } +}; + +} // end anonymous namespace + +Cache* NewLRUCache(size_t capacity) { + return new ShardedLRUCache(capacity); +} + +} // namespace leveldb diff --git a/src/leveldb/util/cache_test.cc b/src/leveldb/util/cache_test.cc new file mode 100644 index 0000000..4371671 --- /dev/null +++ b/src/leveldb/util/cache_test.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/cache.h" + +#include +#include "util/coding.h" +#include "util/testharness.h" + +namespace leveldb { + +// Conversions between numeric keys/values and the types expected by Cache. +static std::string EncodeKey(int k) { + std::string result; + PutFixed32(&result, k); + return result; +} +static int DecodeKey(const Slice& k) { + assert(k.size() == 4); + return DecodeFixed32(k.data()); +} +static void* EncodeValue(uintptr_t v) { return reinterpret_cast(v); } +static int DecodeValue(void* v) { return reinterpret_cast(v); } + +class CacheTest { + public: + static CacheTest* current_; + + static void Deleter(const Slice& key, void* v) { + current_->deleted_keys_.push_back(DecodeKey(key)); + current_->deleted_values_.push_back(DecodeValue(v)); + } + + static const int kCacheSize = 1000; + std::vector deleted_keys_; + std::vector deleted_values_; + Cache* cache_; + + CacheTest() : cache_(NewLRUCache(kCacheSize)) { + current_ = this; + } + + ~CacheTest() { + delete cache_; + } + + int Lookup(int key) { + Cache::Handle* handle = cache_->Lookup(EncodeKey(key)); + const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle)); + if (handle != NULL) { + cache_->Release(handle); + } + return r; + } + + void Insert(int key, int value, int charge = 1) { + cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge, + &CacheTest::Deleter)); + } + + void Erase(int key) { + cache_->Erase(EncodeKey(key)); + } +}; +CacheTest* CacheTest::current_; + +TEST(CacheTest, HitAndMiss) { + ASSERT_EQ(-1, Lookup(100)); + + Insert(100, 101); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(200, 201); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(100, 102); + ASSERT_EQ(102, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); +} + +TEST(CacheTest, Erase) { + Erase(200); + ASSERT_EQ(0, deleted_keys_.size()); + + Insert(100, 101); + Insert(200, 201); + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); +} + +TEST(CacheTest, EntriesArePinned) { + Insert(100, 101); + Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); + + Insert(100, 102); + Cache::Handle* h2 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(102, DecodeValue(cache_->Value(h2))); + ASSERT_EQ(0, deleted_keys_.size()); + + cache_->Release(h1); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(1, deleted_keys_.size()); + + cache_->Release(h2); + ASSERT_EQ(2, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[1]); + ASSERT_EQ(102, deleted_values_[1]); +} + +TEST(CacheTest, EvictionPolicy) { + Insert(100, 101); + Insert(200, 201); + + // Frequently used entry must be kept around + for (int i = 0; i < kCacheSize + 100; i++) { + Insert(1000+i, 2000+i); + ASSERT_EQ(2000+i, Lookup(1000+i)); + ASSERT_EQ(101, Lookup(100)); + } + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); +} + +TEST(CacheTest, HeavyEntries) { + // Add a bunch of light and heavy entries and then count the combined + // size of items still in the cache, which must be approximately the + // same as the total capacity. + const int kLight = 1; + const int kHeavy = 10; + int added = 0; + int index = 0; + while (added < 2*kCacheSize) { + const int weight = (index & 1) ? kLight : kHeavy; + Insert(index, 1000+index, weight); + added += weight; + index++; + } + + int cached_weight = 0; + for (int i = 0; i < index; i++) { + const int weight = (i & 1 ? kLight : kHeavy); + int r = Lookup(i); + if (r >= 0) { + cached_weight += weight; + ASSERT_EQ(1000+i, r); + } + } + ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10); +} + +TEST(CacheTest, NewId) { + uint64_t a = cache_->NewId(); + uint64_t b = cache_->NewId(); + ASSERT_NE(a, b); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/coding.cc b/src/leveldb/util/coding.cc new file mode 100644 index 0000000..21e3186 --- /dev/null +++ b/src/leveldb/util/coding.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +namespace leveldb { + +void EncodeFixed32(char* buf, uint32_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + } +} + +void EncodeFixed64(char* buf, uint64_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + buf[4] = (value >> 32) & 0xff; + buf[5] = (value >> 40) & 0xff; + buf[6] = (value >> 48) & 0xff; + buf[7] = (value >> 56) & 0xff; + } +} + +void PutFixed32(std::string* dst, uint32_t value) { + char buf[sizeof(value)]; + EncodeFixed32(buf, value); + dst->append(buf, sizeof(buf)); +} + +void PutFixed64(std::string* dst, uint64_t value) { + char buf[sizeof(value)]; + EncodeFixed64(buf, value); + dst->append(buf, sizeof(buf)); +} + +char* EncodeVarint32(char* dst, uint32_t v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(dst); + static const int B = 128; + if (v < (1<<7)) { + *(ptr++) = v; + } else if (v < (1<<14)) { + *(ptr++) = v | B; + *(ptr++) = v>>7; + } else if (v < (1<<21)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = v>>14; + } else if (v < (1<<28)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = v>>21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = (v>>21) | B; + *(ptr++) = v>>28; + } + return reinterpret_cast(ptr); +} + +void PutVarint32(std::string* dst, uint32_t v) { + char buf[5]; + char* ptr = EncodeVarint32(buf, v); + dst->append(buf, ptr - buf); +} + +char* EncodeVarint64(char* dst, uint64_t v) { + static const int B = 128; + unsigned char* ptr = reinterpret_cast(dst); + while (v >= B) { + *(ptr++) = (v & (B-1)) | B; + v >>= 7; + } + *(ptr++) = static_cast(v); + return reinterpret_cast(ptr); +} + +void PutVarint64(std::string* dst, uint64_t v) { + char buf[10]; + char* ptr = EncodeVarint64(buf, v); + dst->append(buf, ptr - buf); +} + +void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { + PutVarint32(dst, value.size()); + dst->append(value.data(), value.size()); +} + +int VarintLength(uint64_t v) { + int len = 1; + while (v >= 128) { + v >>= 7; + len++; + } + return len; +} + +const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value) { + uint32_t result = 0; + for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { + uint32_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint32(Slice* input, uint32_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint32Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { + uint64_t result = 0; + for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { + uint64_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint64(Slice* input, uint64_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint64Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetLengthPrefixedSlice(const char* p, const char* limit, + Slice* result) { + uint32_t len; + p = GetVarint32Ptr(p, limit, &len); + if (p == NULL) return NULL; + if (p + len > limit) return NULL; + *result = Slice(p, len); + return p + len; +} + +bool GetLengthPrefixedSlice(Slice* input, Slice* result) { + uint32_t len; + if (GetVarint32(input, &len) && + input->size() >= len) { + *result = Slice(input->data(), len); + input->remove_prefix(len); + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/src/leveldb/util/coding.h b/src/leveldb/util/coding.h new file mode 100644 index 0000000..3993c4a --- /dev/null +++ b/src/leveldb/util/coding.h @@ -0,0 +1,104 @@ +// 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. +// +// Endian-neutral encoding: +// * Fixed-length numbers are encoded with least-significant byte first +// * In addition we support variable length "varint" encoding +// * Strings are encoded prefixed by their length in varint format + +#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ +#define STORAGE_LEVELDB_UTIL_CODING_H_ + +#include +#include +#include +#include "leveldb/slice.h" +#include "port/port.h" + +namespace leveldb { + +// Standard Put... routines append to a string +extern void PutFixed32(std::string* dst, uint32_t value); +extern void PutFixed64(std::string* dst, uint64_t value); +extern void PutVarint32(std::string* dst, uint32_t value); +extern void PutVarint64(std::string* dst, uint64_t value); +extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value); + +// Standard Get... routines parse a value from the beginning of a Slice +// and advance the slice past the parsed value. +extern bool GetVarint32(Slice* input, uint32_t* value); +extern bool GetVarint64(Slice* input, uint64_t* value); +extern bool GetLengthPrefixedSlice(Slice* input, Slice* result); + +// Pointer-based variants of GetVarint... These either store a value +// in *v and return a pointer just past the parsed value, or return +// NULL on error. These routines only look at bytes in the range +// [p..limit-1] +extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v); +extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v); + +// Returns the length of the varint32 or varint64 encoding of "v" +extern int VarintLength(uint64_t v); + +// Lower-level versions of Put... that write directly into a character buffer +// REQUIRES: dst has enough space for the value being written +extern void EncodeFixed32(char* dst, uint32_t value); +extern void EncodeFixed64(char* dst, uint64_t value); + +// Lower-level versions of Put... that write directly into a character buffer +// and return a pointer just past the last byte written. +// REQUIRES: dst has enough space for the value being written +extern char* EncodeVarint32(char* dst, uint32_t value); +extern char* EncodeVarint64(char* dst, uint64_t value); + +// Lower-level versions of Get... that read directly from a character buffer +// without any bounds checking. + +inline uint32_t DecodeFixed32(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint32_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + return ((static_cast(static_cast(ptr[0]))) + | (static_cast(static_cast(ptr[1])) << 8) + | (static_cast(static_cast(ptr[2])) << 16) + | (static_cast(static_cast(ptr[3])) << 24)); + } +} + +inline uint64_t DecodeFixed64(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint64_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + uint64_t lo = DecodeFixed32(ptr); + uint64_t hi = DecodeFixed32(ptr + 4); + return (hi << 32) | lo; + } +} + +// Internal routine for use by fallback path of GetVarint32Ptr +extern const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value); +inline const char* GetVarint32Ptr(const char* p, + const char* limit, + uint32_t* value) { + if (p < limit) { + uint32_t result = *(reinterpret_cast(p)); + if ((result & 128) == 0) { + *value = result; + return p + 1; + } + } + return GetVarint32PtrFallback(p, limit, value); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/src/leveldb/util/coding_test.cc b/src/leveldb/util/coding_test.cc new file mode 100644 index 0000000..fb5726e --- /dev/null +++ b/src/leveldb/util/coding_test.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +#include "util/testharness.h" + +namespace leveldb { + +class Coding { }; + +TEST(Coding, Fixed32) { + std::string s; + for (uint32_t v = 0; v < 100000; v++) { + PutFixed32(&s, v); + } + + const char* p = s.data(); + for (uint32_t v = 0; v < 100000; v++) { + uint32_t actual = DecodeFixed32(p); + ASSERT_EQ(v, actual); + p += sizeof(uint32_t); + } +} + +TEST(Coding, Fixed64) { + std::string s; + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + PutFixed64(&s, v - 1); + PutFixed64(&s, v + 0); + PutFixed64(&s, v + 1); + } + + const char* p = s.data(); + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + uint64_t actual; + actual = DecodeFixed64(p); + ASSERT_EQ(v-1, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+0, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+1, actual); + p += sizeof(uint64_t); + } +} + +// Test that encoding routines generate little-endian encodings +TEST(Coding, EncodingOutput) { + std::string dst; + PutFixed32(&dst, 0x04030201); + ASSERT_EQ(4, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + + dst.clear(); + PutFixed64(&dst, 0x0807060504030201ull); + ASSERT_EQ(8, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + ASSERT_EQ(0x05, static_cast(dst[4])); + ASSERT_EQ(0x06, static_cast(dst[5])); + ASSERT_EQ(0x07, static_cast(dst[6])); + ASSERT_EQ(0x08, static_cast(dst[7])); +} + +TEST(Coding, Varint32) { + std::string s; + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t v = (i / 32) << (i % 32); + PutVarint32(&s, v); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t expected = (i / 32) << (i % 32); + uint32_t actual; + const char* start = p; + p = GetVarint32Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(expected, actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, s.data() + s.size()); +} + +TEST(Coding, Varint64) { + // Construct the list of values to check + std::vector values; + // Some special values + values.push_back(0); + values.push_back(100); + values.push_back(~static_cast(0)); + values.push_back(~static_cast(0) - 1); + for (uint32_t k = 0; k < 64; k++) { + // Test values near powers of two + const uint64_t power = 1ull << k; + values.push_back(power); + values.push_back(power-1); + values.push_back(power+1); + } + + std::string s; + for (int i = 0; i < values.size(); i++) { + PutVarint64(&s, values[i]); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (int i = 0; i < values.size(); i++) { + ASSERT_TRUE(p < limit); + uint64_t actual; + const char* start = p; + p = GetVarint64Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(values[i], actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, limit); + +} + +TEST(Coding, Varint32Overflow) { + uint32_t result; + std::string input("\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint32Truncation) { + uint32_t large_value = (1u << 31) + 100; + std::string s; + PutVarint32(&s, large_value); + uint32_t result; + for (int len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Varint64Overflow) { + uint64_t result; + std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint64Truncation) { + uint64_t large_value = (1ull << 63) + 100ull; + std::string s; + PutVarint64(&s, large_value); + uint64_t result; + for (int len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Strings) { + std::string s; + PutLengthPrefixedSlice(&s, Slice("")); + PutLengthPrefixedSlice(&s, Slice("foo")); + PutLengthPrefixedSlice(&s, Slice("bar")); + PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x'))); + + Slice input(s); + Slice v; + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("foo", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("bar", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ(std::string(200, 'x'), v.ToString()); + ASSERT_EQ("", input.ToString()); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/comparator.cc b/src/leveldb/util/comparator.cc new file mode 100644 index 0000000..4b7b572 --- /dev/null +++ b/src/leveldb/util/comparator.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" + +namespace leveldb { + +Comparator::~Comparator() { } + +namespace { +class BytewiseComparatorImpl : public Comparator { + public: + BytewiseComparatorImpl() { } + + virtual const char* Name() const { + return "leveldb.BytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return a.compare(b); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Find length of common prefix + size_t min_length = std::min(start->size(), limit.size()); + size_t diff_index = 0; + while ((diff_index < min_length) && + ((*start)[diff_index] == limit[diff_index])) { + diff_index++; + } + + if (diff_index >= min_length) { + // Do not shorten if one string is a prefix of the other + } else { + uint8_t diff_byte = static_cast((*start)[diff_index]); + if (diff_byte < static_cast(0xff) && + diff_byte + 1 < static_cast(limit[diff_index])) { + (*start)[diff_index]++; + start->resize(diff_index + 1); + assert(Compare(*start, limit) < 0); + } + } + } + + virtual void FindShortSuccessor(std::string* key) const { + // Find first character that can be incremented + size_t n = key->size(); + for (size_t i = 0; i < n; i++) { + const uint8_t byte = (*key)[i]; + if (byte != static_cast(0xff)) { + (*key)[i] = byte + 1; + key->resize(i+1); + return; + } + } + // *key is a run of 0xffs. Leave it alone. + } +}; +} // namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static const Comparator* bytewise; + +static void InitModule() { + bytewise = new BytewiseComparatorImpl; +} + +const Comparator* BytewiseComparator() { + port::InitOnce(&once, InitModule); + return bytewise; +} + +} // namespace leveldb diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc new file mode 100644 index 0000000..6db9e77 --- /dev/null +++ b/src/leveldb/util/crc32c.cc @@ -0,0 +1,332 @@ +// 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. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. + +#include "util/crc32c.h" + +#include +#include "util/coding.h" + +namespace leveldb { +namespace crc32c { + +static const uint32_t table0_[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; +static const uint32_t table1_[256] = { + 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, + 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, + 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, + 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, + 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, + 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, + 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, + 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, + 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, + 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, + 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, + 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, + 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, + 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, + 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, + 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, + 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, + 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, + 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, + 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, + 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, + 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, + 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, + 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, + 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, + 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, + 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, + 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, + 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, + 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, + 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, + 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, + 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, + 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, + 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, + 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, + 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, + 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, + 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, + 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, + 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, + 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, + 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, + 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, + 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, + 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, + 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, + 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, + 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, + 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, + 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, + 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, + 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, + 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, + 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, + 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, + 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, + 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, + 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, + 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, + 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, + 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, + 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, + 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 +}; +static const uint32_t table2_[256] = { + 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, + 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, + 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, + 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, + 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, + 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, + 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, + 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, + 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, + 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, + 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, + 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, + 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, + 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, + 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, + 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, + 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, + 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, + 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, + 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, + 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, + 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, + 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, + 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, + 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, + 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, + 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, + 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, + 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, + 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, + 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, + 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, + 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, + 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, + 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, + 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, + 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, + 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, + 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, + 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, + 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, + 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, + 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, + 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, + 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, + 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, + 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, + 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, + 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, + 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, + 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, + 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, + 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, + 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, + 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, + 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, + 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, + 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, + 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, + 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, + 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, + 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, + 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, + 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 +}; +static const uint32_t table3_[256] = { + 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, + 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, + 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, + 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, + 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, + 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, + 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, + 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, + 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, + 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, + 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, + 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, + 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, + 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, + 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, + 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, + 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, + 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, + 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, + 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, + 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, + 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, + 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, + 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, + 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, + 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, + 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, + 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, + 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, + 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, + 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, + 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, + 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, + 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, + 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, + 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, + 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, + 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, + 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, + 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, + 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, + 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, + 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, + 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, + 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, + 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, + 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, + 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, + 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, + 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, + 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, + 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, + 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, + 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, + 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, + 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, + 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, + 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, + 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, + 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, + 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, + 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, + 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, + 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 +}; + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + return DecodeFixed32(reinterpret_cast(p)); +} + +uint32_t Extend(uint32_t crc, const char* buf, size_t size) { + const uint8_t *p = reinterpret_cast(buf); + const uint8_t *e = p + size; + uint32_t l = crc ^ 0xffffffffu; + +#define STEP1 do { \ + int c = (l & 0xff) ^ *p++; \ + l = table0_[c] ^ (l >> 8); \ +} while (0) +#define STEP4 do { \ + uint32_t c = l ^ LE_LOAD32(p); \ + p += 4; \ + l = table3_[c & 0xff] ^ \ + table2_[(c >> 8) & 0xff] ^ \ + table1_[(c >> 16) & 0xff] ^ \ + table0_[c >> 24]; \ +} while (0) + + // Point x at first 4-byte aligned byte in string. This might be + // just past the end of the string. + const uintptr_t pval = reinterpret_cast(p); + const uint8_t* x = reinterpret_cast(((pval + 3) >> 2) << 2); + if (x <= e) { + // Process bytes until finished or p is 4-byte aligned + while (p != x) { + STEP1; + } + } + // Process bytes 16 at a time + while ((e-p) >= 16) { + STEP4; STEP4; STEP4; STEP4; + } + // Process bytes 4 at a time + while ((e-p) >= 4) { + STEP4; + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP4 +#undef STEP1 + return l ^ 0xffffffffu; +} + +} // namespace crc32c +} // namespace leveldb diff --git a/src/leveldb/util/crc32c.h b/src/leveldb/util/crc32c.h new file mode 100644 index 0000000..1d7e5c0 --- /dev/null +++ b/src/leveldb/util/crc32c.h @@ -0,0 +1,45 @@ +// 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_UTIL_CRC32C_H_ +#define STORAGE_LEVELDB_UTIL_CRC32C_H_ + +#include +#include + +namespace leveldb { +namespace crc32c { + +// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the +// crc32c of some string A. Extend() is often used to maintain the +// crc32c of a stream of data. +extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); + +// Return the crc32c of data[0,n-1] +inline uint32_t Value(const char* data, size_t n) { + return Extend(0, data, n); +} + +static const uint32_t kMaskDelta = 0xa282ead8ul; + +// Return a masked representation of crc. +// +// Motivation: it is problematic to compute the CRC of a string that +// contains embedded CRCs. Therefore we recommend that CRCs stored +// somewhere (e.g., in files) should be masked before being stored. +inline uint32_t Mask(uint32_t crc) { + // Rotate right by 15 bits and add a constant. + return ((crc >> 15) | (crc << 17)) + kMaskDelta; +} + +// Return the crc whose masked representation is masked_crc. +inline uint32_t Unmask(uint32_t masked_crc) { + uint32_t rot = masked_crc - kMaskDelta; + return ((rot >> 17) | (rot << 15)); +} + +} // namespace crc32c +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/src/leveldb/util/crc32c_test.cc b/src/leveldb/util/crc32c_test.cc new file mode 100644 index 0000000..4b957ee --- /dev/null +++ b/src/leveldb/util/crc32c_test.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/crc32c.h" +#include "util/testharness.h" + +namespace leveldb { +namespace crc32c { + +class CRC { }; + +TEST(CRC, StandardResults) { + // From rfc3720 section B.4. + char buf[32]; + + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf))); + + memset(buf, 0xff, sizeof(buf)); + ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = i; + } + ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = 31 - i; + } + ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf))); + + unsigned char data[48] = { + 0x01, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x18, + 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + ASSERT_EQ(0xd9963a56, Value(reinterpret_cast(data), sizeof(data))); +} + +TEST(CRC, Values) { + ASSERT_NE(Value("a", 1), Value("foo", 3)); +} + +TEST(CRC, Extend) { + ASSERT_EQ(Value("hello world", 11), + Extend(Value("hello ", 6), "world", 5)); +} + +TEST(CRC, Mask) { + uint32_t crc = Value("foo", 3); + ASSERT_NE(crc, Mask(crc)); + ASSERT_NE(crc, Mask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc))))); +} + +} // namespace crc32c +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/env.cc b/src/leveldb/util/env.cc new file mode 100644 index 0000000..c2600e9 --- /dev/null +++ b/src/leveldb/util/env.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +namespace leveldb { + +Env::~Env() { +} + +SequentialFile::~SequentialFile() { +} + +RandomAccessFile::~RandomAccessFile() { +} + +WritableFile::~WritableFile() { +} + +Logger::~Logger() { +} + +FileLock::~FileLock() { +} + +void Log(Logger* info_log, const char* format, ...) { + if (info_log != NULL) { + va_list ap; + va_start(ap, format); + info_log->Logv(format, ap); + va_end(ap); + } +} + +static Status DoWriteStringToFile(Env* env, const Slice& data, + const std::string& fname, + bool should_sync) { + WritableFile* file; + Status s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + s = file->Append(data); + if (s.ok() && should_sync) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; // Will auto-close if we did not close above + if (!s.ok()) { + env->DeleteFile(fname); + } + return s; +} + +Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, false); +} + +Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, true); +} + +Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { + data->clear(); + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + static const int kBufferSize = 8192; + char* space = new char[kBufferSize]; + while (true) { + Slice fragment; + s = file->Read(kBufferSize, &fragment, space); + if (!s.ok()) { + break; + } + data->append(fragment.data(), fragment.size()); + if (fragment.empty()) { + break; + } + } + delete[] space; + delete file; + return s; +} + +EnvWrapper::~EnvWrapper() { +} + +} // namespace leveldb diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc new file mode 100644 index 0000000..aff5df9 --- /dev/null +++ b/src/leveldb/util/env_posix.cc @@ -0,0 +1,825 @@ +// 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. +#if !defined(LEVELDB_PLATFORM_WINDOWS) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(LEVELDB_PLATFORM_ANDROID) +#include +#endif +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/posix_logger.h" + +namespace leveldb { + +namespace { + +static Status IOError(const std::string& context, int err_number) { + return Status::IOError(context, strerror(err_number)); +} + +class PosixSequentialFile: public SequentialFile { + private: + std::string filename_; + FILE* file_; + + public: + PosixSequentialFile(const std::string& fname, FILE* f) + : filename_(fname), file_(f) { } + virtual ~PosixSequentialFile() { fclose(file_); } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s; + size_t r = fread_unlocked(scratch, 1, n, file_); + *result = Slice(scratch, r); + if (r < n) { + if (feof(file_)) { + // We leave status as ok if we hit the end of the file + } else { + // A partial read with an error: return a non-ok status + s = IOError(filename_, errno); + } + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (fseek(file_, n, SEEK_CUR)) { + return IOError(filename_, errno); + } + return Status::OK(); + } +}; + +// pread() based random-access +class PosixRandomAccessFile: public RandomAccessFile { + private: + std::string filename_; + int fd_; + + public: + PosixRandomAccessFile(const std::string& fname, int fd) + : filename_(fname), fd_(fd) { } + virtual ~PosixRandomAccessFile() { close(fd_); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + ssize_t r = pread(fd_, scratch, n, static_cast(offset)); + *result = Slice(scratch, (r < 0) ? 0 : r); + if (r < 0) { + // An error: return a non-ok status + s = IOError(filename_, errno); + } + return s; + } +}; + +// Helper class to limit mmap file usage so that we do not end up +// running out virtual memory or running into kernel performance +// problems for very large databases. +class MmapLimiter { + public: + // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. + MmapLimiter() { + SetAllowed(sizeof(void*) >= 8 ? 1000 : 0); + } + + // If another mmap slot is available, acquire it and return true. + // Else return false. + bool Acquire() { + if (GetAllowed() <= 0) { + return false; + } + MutexLock l(&mu_); + intptr_t x = GetAllowed(); + if (x <= 0) { + return false; + } else { + SetAllowed(x - 1); + return true; + } + } + + // Release a slot acquired by a previous call to Acquire() that returned true. + void Release() { + MutexLock l(&mu_); + SetAllowed(GetAllowed() + 1); + } + + private: + port::Mutex mu_; + port::AtomicPointer allowed_; + + intptr_t GetAllowed() const { + return reinterpret_cast(allowed_.Acquire_Load()); + } + + // REQUIRES: mu_ must be held + void SetAllowed(intptr_t v) { + allowed_.Release_Store(reinterpret_cast(v)); + } + + MmapLimiter(const MmapLimiter&); + void operator=(const MmapLimiter&); +}; + +// mmap() based random-access +class PosixMmapReadableFile: public RandomAccessFile { + private: + std::string filename_; + void* mmapped_region_; + size_t length_; + MmapLimiter* limiter_; + + public: + // base[0,length-1] contains the mmapped contents of the file. + PosixMmapReadableFile(const std::string& fname, void* base, size_t length, + MmapLimiter* limiter) + : filename_(fname), mmapped_region_(base), length_(length), + limiter_(limiter) { + } + + virtual ~PosixMmapReadableFile() { + munmap(mmapped_region_, length_); + limiter_->Release(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + if (offset + n > length_) { + *result = Slice(); + s = IOError(filename_, EINVAL); + } else { + *result = Slice(reinterpret_cast(mmapped_region_) + offset, n); + } + return s; + } +}; + +// We preallocate up to an extra megabyte and use memcpy to append new +// data to the file. This is safe since we either properly close the +// file before reading from it, or for log files, the reading code +// knows enough to skip zero suffixes. +class PosixMmapFile : public WritableFile { + private: + std::string filename_; + int fd_; + size_t page_size_; + size_t map_size_; // How much extra memory to map at a time + char* base_; // The mapped region + char* limit_; // Limit of the mapped region + char* dst_; // Where to write next (in range [base_,limit_]) + char* last_sync_; // Where have we synced up to + uint64_t file_offset_; // Offset of base_ in file + + // Have we done an munmap of unsynced data? + bool pending_sync_; + + // Roundup x to a multiple of y + static size_t Roundup(size_t x, size_t y) { + return ((x + y - 1) / y) * y; + } + + size_t TruncateToPageBoundary(size_t s) { + s -= (s & (page_size_ - 1)); + assert((s % page_size_) == 0); + return s; + } + + bool UnmapCurrentRegion() { + bool result = true; + if (base_ != NULL) { + if (last_sync_ < limit_) { + // Defer syncing this data until next Sync() call, if any + pending_sync_ = true; + } + if (munmap(base_, limit_ - base_) != 0) { + result = false; + } + file_offset_ += limit_ - base_; + base_ = NULL; + limit_ = NULL; + last_sync_ = NULL; + dst_ = NULL; + + // Increase the amount we map the next time, but capped at 1MB + if (map_size_ < (1<<20)) { + map_size_ *= 2; + } + } + return result; + } + + bool MapNewRegion() { + assert(base_ == NULL); + if (ftruncate(fd_, file_offset_ + map_size_) < 0) { + return false; + } + void* ptr = mmap(NULL, map_size_, PROT_READ | PROT_WRITE, MAP_SHARED, + fd_, file_offset_); + if (ptr == MAP_FAILED) { + return false; + } + base_ = reinterpret_cast(ptr); + limit_ = base_ + map_size_; + dst_ = base_; + last_sync_ = base_; + return true; + } + + public: + PosixMmapFile(const std::string& fname, int fd, size_t page_size) + : filename_(fname), + fd_(fd), + page_size_(page_size), + map_size_(Roundup(65536, page_size)), + base_(NULL), + limit_(NULL), + dst_(NULL), + last_sync_(NULL), + file_offset_(0), + pending_sync_(false) { + assert((page_size & (page_size - 1)) == 0); + } + + + ~PosixMmapFile() { + if (fd_ >= 0) { + PosixMmapFile::Close(); + } + } + + virtual Status Append(const Slice& data) { + const char* src = data.data(); + size_t left = data.size(); + while (left > 0) { + assert(base_ <= dst_); + assert(dst_ <= limit_); + size_t avail = limit_ - dst_; + if (avail == 0) { + if (!UnmapCurrentRegion() || + !MapNewRegion()) { + return IOError(filename_, errno); + } + } + + size_t n = (left <= avail) ? left : avail; + memcpy(dst_, src, n); + dst_ += n; + src += n; + left -= n; + } + return Status::OK(); + } + + virtual Status Close() { + Status s; + size_t unused = limit_ - dst_; + if (!UnmapCurrentRegion()) { + s = IOError(filename_, errno); + } else if (unused > 0) { + // Trim the extra space at the end of the file + if (ftruncate(fd_, file_offset_ - unused) < 0) { + s = IOError(filename_, errno); + } + } + + if (close(fd_) < 0) { + if (s.ok()) { + s = IOError(filename_, errno); + } + } + + fd_ = -1; + base_ = NULL; + limit_ = NULL; + return s; + } + + virtual Status Flush() { + return Status::OK(); + } + + Status SyncDirIfManifest() { + const char* f = filename_.c_str(); + const char* sep = strrchr(f, '/'); + Slice basename; + std::string dir; + if (sep == NULL) { + dir = "."; + basename = f; + } else { + dir = std::string(f, sep - f); + basename = sep + 1; + } + Status s; + if (basename.starts_with("MANIFEST")) { + int fd = open(dir.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(dir, errno); + } else { + if (fsync(fd) < 0) { + s = IOError(dir, errno); + } + close(fd); + } + } + return s; + } + + virtual Status Sync() { + // Ensure new files referred to by the manifest are in the filesystem. + Status s = SyncDirIfManifest(); + if (!s.ok()) { + return s; + } + + if (pending_sync_) { + // Some unmapped data was not synced + pending_sync_ = false; + if (fdatasync(fd_) < 0) { + s = IOError(filename_, errno); + } + } + + if (dst_ > last_sync_) { + // Find the beginnings of the pages that contain the first and last + // bytes to be synced. + size_t p1 = TruncateToPageBoundary(last_sync_ - base_); + size_t p2 = TruncateToPageBoundary(dst_ - base_ - 1); + last_sync_ = dst_; + if (msync(base_ + p1, p2 - p1 + page_size_, MS_SYNC) < 0) { + s = IOError(filename_, errno); + } + } + + return s; + } +}; + +#if defined(OS_MACOSX) +class PosixWriteableFile : public WritableFile { + private: + std::string filename_; + int fd_; + public: + PosixWriteableFile(const std::string& fname, int fd) + : filename_(fname), + fd_(fd) + { } + + + ~PosixWriteableFile() { + if (fd_ >= 0) { + PosixWriteableFile::Close(); + } + } + + virtual Status Append(const Slice& data) { + Status s; + int ret; + ret = write(fd_, data.data(), data.size()); + if (ret < 0) { + s = IOError(filename_, errno); + } else if (ret < data.size()) { + s = Status::IOError(filename_, "short write"); + } + + return s; + } + + virtual Status Close() { + Status s; + if (close(fd_) < 0) { + s = IOError(filename_, errno); + } + fd_ = -1; + return s; + } + + virtual Status Flush() { + return Status::OK(); + } + + Status SyncDirIfManifest() { + const char* f = filename_.c_str(); + const char* sep = strrchr(f, '/'); + Slice basename; + std::string dir; + if (sep == NULL) { + dir = "."; + basename = f; + } else { + dir = std::string(f, sep - f); + basename = sep + 1; + } + Status s; + if (basename.starts_with("MANIFEST")) { + int fd = open(dir.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(dir, errno); + } else { + if (fsync(fd) < 0) { + s = IOError(dir, errno); + } + close(fd); + } + } + return s; + } + + virtual Status Sync() { + // Ensure new files referred to by the manifest are in the filesystem. + Status s = SyncDirIfManifest(); + if (!s.ok()) { + return s; + } + + if (fdatasync(fd_) < 0) { + s = IOError(filename_, errno); + } + + return s; + } +}; +#endif + +static int LockOrUnlock(int fd, bool lock) { + errno = 0; + struct flock f; + memset(&f, 0, sizeof(f)); + f.l_type = (lock ? F_WRLCK : F_UNLCK); + f.l_whence = SEEK_SET; + f.l_start = 0; + f.l_len = 0; // Lock/unlock entire file + return fcntl(fd, F_SETLK, &f); +} + +class PosixFileLock : public FileLock { + public: + int fd_; + std::string name_; +}; + +// Set of locked files. We keep a separate set instead of just +// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide +// any protection against multiple uses from the same process. +class PosixLockTable { + private: + port::Mutex mu_; + std::set locked_files_; + public: + bool Insert(const std::string& fname) { + MutexLock l(&mu_); + return locked_files_.insert(fname).second; + } + void Remove(const std::string& fname) { + MutexLock l(&mu_); + locked_files_.erase(fname); + } +}; + +class PosixEnv : public Env { + public: + PosixEnv(); + virtual ~PosixEnv() { + fprintf(stderr, "Destroying Env::Default()\n"); + abort(); + } + + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + FILE* f = fopen(fname.c_str(), "r"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixSequentialFile(fname, f); + return Status::OK(); + } + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + *result = NULL; + Status s; + int fd = open(fname.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(fname, errno); +#if !defined(OS_MACOSX) + } else if (mmap_limit_.Acquire()) { + uint64_t size; + s = GetFileSize(fname, &size); + if (s.ok()) { + void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (base != MAP_FAILED) { + *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_); + } else { + s = IOError(fname, errno); + } + } + close(fd); + if (!s.ok()) { + mmap_limit_.Release(); + } +#endif + } else { + *result = new PosixRandomAccessFile(fname, fd); + } + return s; + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + Status s; + const int fd = open(fname.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644); + if (fd < 0) { + *result = NULL; + s = IOError(fname, errno); + } else { +#if defined(OS_MACOSX) + *result = new PosixWriteableFile(fname, fd); +#else + *result = new PosixMmapFile(fname, fd, page_size_); +#endif + } + return s; + } + + virtual bool FileExists(const std::string& fname) { + return access(fname.c_str(), F_OK) == 0; + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + result->clear(); + DIR* d = opendir(dir.c_str()); + if (d == NULL) { + return IOError(dir, errno); + } + struct dirent* entry; + while ((entry = readdir(d)) != NULL) { + result->push_back(entry->d_name); + } + closedir(d); + return Status::OK(); + } + + virtual Status DeleteFile(const std::string& fname) { + Status result; + if (unlink(fname.c_str()) != 0) { + result = IOError(fname, errno); + } + return result; + } + + virtual Status CreateDir(const std::string& name) { + Status result; + if (mkdir(name.c_str(), 0755) != 0) { + result = IOError(name, errno); + } + return result; + } + + virtual Status DeleteDir(const std::string& name) { + Status result; + if (rmdir(name.c_str()) != 0) { + result = IOError(name, errno); + } + return result; + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* size) { + Status s; + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + *size = 0; + s = IOError(fname, errno); + } else { + *size = sbuf.st_size; + } + return s; + } + + virtual Status RenameFile(const std::string& src, const std::string& target) { + Status result; + if (rename(src.c_str(), target.c_str()) != 0) { + result = IOError(src, errno); + } + return result; + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = NULL; + Status result; + int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644); + if (fd < 0) { + result = IOError(fname, errno); + } else if (!locks_.Insert(fname)) { + close(fd); + result = Status::IOError("lock " + fname, "already held by process"); + } else if (LockOrUnlock(fd, true) == -1) { + result = IOError("lock " + fname, errno); + close(fd); + locks_.Remove(fname); + } else { + PosixFileLock* my_lock = new PosixFileLock; + my_lock->fd_ = fd; + my_lock->name_ = fname; + *lock = my_lock; + } + return result; + } + + virtual Status UnlockFile(FileLock* lock) { + PosixFileLock* my_lock = reinterpret_cast(lock); + Status result; + if (LockOrUnlock(my_lock->fd_, false) == -1) { + result = IOError("unlock", errno); + } + locks_.Remove(my_lock->name_); + close(my_lock->fd_); + delete my_lock; + return result; + } + + virtual void Schedule(void (*function)(void*), void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* result) { + const char* env = getenv("TEST_TMPDIR"); + if (env && env[0] != '\0') { + *result = env; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); + *result = buf; + } + // Directory may already exist + CreateDir(*result); + return Status::OK(); + } + + static uint64_t gettid() { + pthread_t tid = pthread_self(); + uint64_t thread_id = 0; + memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); + return thread_id; + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + FILE* f = fopen(fname.c_str(), "w"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixLogger(f, &PosixEnv::gettid); + return Status::OK(); + } + } + + virtual uint64_t NowMicros() { + struct timeval tv; + gettimeofday(&tv, NULL); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + } + + virtual void SleepForMicroseconds(int micros) { + usleep(micros); + } + + private: + void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } + } + + // BGThread() is the body of the background thread + void BGThread(); + static void* BGThreadWrapper(void* arg) { + reinterpret_cast(arg)->BGThread(); + return NULL; + } + + size_t page_size_; + pthread_mutex_t mu_; + pthread_cond_t bgsignal_; + pthread_t bgthread_; + bool started_bgthread_; + + // Entry per Schedule() call + struct BGItem { void* arg; void (*function)(void*); }; + typedef std::deque BGQueue; + BGQueue queue_; + + PosixLockTable locks_; + MmapLimiter mmap_limit_; +}; + +PosixEnv::PosixEnv() : page_size_(getpagesize()), + started_bgthread_(false) { + PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); + PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); +} + +void PosixEnv::Schedule(void (*function)(void*), void* arg) { + PthreadCall("lock", pthread_mutex_lock(&mu_)); + + // Start background thread if necessary + if (!started_bgthread_) { + started_bgthread_ = true; + PthreadCall( + "create thread", + pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this)); + } + + // If the queue is currently empty, the background thread may currently be + // waiting. + if (queue_.empty()) { + PthreadCall("signal", pthread_cond_signal(&bgsignal_)); + } + + // Add to priority queue + queue_.push_back(BGItem()); + queue_.back().function = function; + queue_.back().arg = arg; + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); +} + +void PosixEnv::BGThread() { + while (true) { + // Wait until there is an item that is ready to run + PthreadCall("lock", pthread_mutex_lock(&mu_)); + while (queue_.empty()) { + PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_)); + } + + void (*function)(void*) = queue_.front().function; + void* arg = queue_.front().arg; + queue_.pop_front(); + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); + (*function)(arg); + } +} + +namespace { +struct StartThreadState { + void (*user_function)(void*); + void* arg; +}; +} +static void* StartThreadWrapper(void* arg) { + StartThreadState* state = reinterpret_cast(arg); + state->user_function(state->arg); + delete state; + return NULL; +} + +void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { + pthread_t t; + StartThreadState* state = new StartThreadState; + state->user_function = function; + state->arg = arg; + PthreadCall("start thread", + pthread_create(&t, NULL, &StartThreadWrapper, state)); +} + +} // namespace + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new PosixEnv; } + +Env* Env::Default() { + pthread_once(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#endif diff --git a/src/leveldb/util/env_test.cc b/src/leveldb/util/env_test.cc new file mode 100644 index 0000000..b72cb44 --- /dev/null +++ b/src/leveldb/util/env_test.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +#include "port/port.h" +#include "util/testharness.h" + +namespace leveldb { + +static const int kDelayMicros = 100000; + +class EnvPosixTest { + private: + port::Mutex mu_; + std::string events_; + + public: + Env* env_; + EnvPosixTest() : env_(Env::Default()) { } +}; + +static void SetBool(void* ptr) { + reinterpret_cast(ptr)->NoBarrier_Store(ptr); +} + +TEST(EnvPosixTest, RunImmediately) { + port::AtomicPointer called (NULL); + env_->Schedule(&SetBool, &called); + Env::Default()->SleepForMicroseconds(kDelayMicros); + ASSERT_TRUE(called.NoBarrier_Load() != NULL); +} + +TEST(EnvPosixTest, RunMany) { + port::AtomicPointer last_id (NULL); + + struct CB { + port::AtomicPointer* last_id_ptr; // Pointer to shared slot + uintptr_t id; // Order# for the execution of this callback + + CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } + + static void Run(void* v) { + CB* cb = reinterpret_cast(v); + void* cur = cb->last_id_ptr->NoBarrier_Load(); + ASSERT_EQ(cb->id-1, reinterpret_cast(cur)); + cb->last_id_ptr->Release_Store(reinterpret_cast(cb->id)); + } + }; + + // Schedule in different order than start time + CB cb1(&last_id, 1); + CB cb2(&last_id, 2); + CB cb3(&last_id, 3); + CB cb4(&last_id, 4); + env_->Schedule(&CB::Run, &cb1); + env_->Schedule(&CB::Run, &cb2); + env_->Schedule(&CB::Run, &cb3); + env_->Schedule(&CB::Run, &cb4); + + Env::Default()->SleepForMicroseconds(kDelayMicros); + void* cur = last_id.Acquire_Load(); + ASSERT_EQ(4, reinterpret_cast(cur)); +} + +struct State { + port::Mutex mu; + int val; + int num_running; +}; + +static void ThreadBody(void* arg) { + State* s = reinterpret_cast(arg); + s->mu.Lock(); + s->val += 1; + s->num_running -= 1; + s->mu.Unlock(); +} + +TEST(EnvPosixTest, StartThread) { + State state; + state.val = 0; + state.num_running = 3; + for (int i = 0; i < 3; i++) { + env_->StartThread(&ThreadBody, &state); + } + while (true) { + state.mu.Lock(); + int num = state.num_running; + state.mu.Unlock(); + if (num == 0) { + break; + } + Env::Default()->SleepForMicroseconds(kDelayMicros); + } + ASSERT_EQ(state.val, 3); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc new file mode 100644 index 0000000..ef2ecae --- /dev/null +++ b/src/leveldb/util/env_win.cc @@ -0,0 +1,1031 @@ +// This file contains source that originates from: +// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h +// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc +// Those files dont' have any explict license headers but the +// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' +// as the license. +#if defined(LEVELDB_PLATFORM_WINDOWS) +#include + + +#include "leveldb/env.h" + +#include "port/port.h" +#include "leveldb/slice.h" +#include "util/logging.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef max +#undef max +#endif + +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +#if defined DeleteFile +#undef DeleteFile +#endif + +//Declarations +namespace leveldb +{ + +namespace Win32 +{ + +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +std::string GetCurrentDir(); +std::wstring GetCurrentDirW(); + +static const std::string CurrentDir = GetCurrentDir(); +static const std::wstring CurrentDirW = GetCurrentDirW(); + +std::string& ModifyPath(std::string& path); +std::wstring& ModifyPath(std::wstring& path); + +std::string GetLastErrSz(); +std::wstring GetLastErrSzW(); + +size_t GetPageSize(); + +typedef void (*ScheduleProc)(void*) ; + +struct WorkItemWrapper +{ + WorkItemWrapper(ScheduleProc proc_,void* content_); + ScheduleProc proc; + void* pContent; +}; + +DWORD WINAPI WorkItemWrapperProc(LPVOID pContent); + +class Win32SequentialFile : public SequentialFile +{ +public: + friend class Win32Env; + virtual ~Win32SequentialFile(); + virtual Status Read(size_t n, Slice* result, char* scratch); + virtual Status Skip(uint64_t n); + BOOL isEnable(); +private: + BOOL _Init(); + void _CleanUp(); + Win32SequentialFile(const std::string& fname); + std::string _filename; + ::HANDLE _hFile; + DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile); +}; + +class Win32RandomAccessFile : public RandomAccessFile +{ +public: + friend class Win32Env; + virtual ~Win32RandomAccessFile(); + virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; + BOOL isEnable(); +private: + BOOL _Init(LPCWSTR path); + void _CleanUp(); + Win32RandomAccessFile(const std::string& fname); + HANDLE _hFile; + const std::string _filename; + DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); +}; + +class Win32MapFile : public WritableFile +{ +public: + Win32MapFile(const std::string& fname); + + ~Win32MapFile(); + virtual Status Append(const Slice& data); + virtual Status Close(); + virtual Status Flush(); + virtual Status Sync(); + BOOL isEnable(); +private: + std::string _filename; + HANDLE _hFile; + size_t _page_size; + size_t _map_size; // How much extra memory to map at a time + char* _base; // The mapped region + HANDLE _base_handle; + char* _limit; // Limit of the mapped region + char* _dst; // Where to write next (in range [base_,limit_]) + char* _last_sync; // Where have we synced up to + uint64_t _file_offset; // Offset of base_ in file + //LARGE_INTEGER file_offset_; + // Have we done an munmap of unsynced data? + bool _pending_sync; + + // Roundup x to a multiple of y + static size_t _Roundup(size_t x, size_t y); + size_t _TruncateToPageBoundary(size_t s); + bool _UnmapCurrentRegion(); + bool _MapNewRegion(); + DISALLOW_COPY_AND_ASSIGN(Win32MapFile); + BOOL _Init(LPCWSTR Path); +}; + +class Win32FileLock : public FileLock +{ +public: + friend class Win32Env; + virtual ~Win32FileLock(); + BOOL isEnable(); +private: + BOOL _Init(LPCWSTR path); + void _CleanUp(); + Win32FileLock(const std::string& fname); + HANDLE _hFile; + std::string _filename; + DISALLOW_COPY_AND_ASSIGN(Win32FileLock); +}; + +class Win32Logger : public Logger +{ +public: + friend class Win32Env; + virtual ~Win32Logger(); + virtual void Logv(const char* format, va_list ap); +private: + explicit Win32Logger(WritableFile* pFile); + WritableFile* _pFileProxy; + DISALLOW_COPY_AND_ASSIGN(Win32Logger); +}; + +class Win32Env : public Env +{ +public: + Win32Env(); + virtual ~Win32Env(); + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result); + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result); + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result); + + virtual bool FileExists(const std::string& fname); + + virtual Status GetChildren(const std::string& dir, + std::vector* result); + + virtual Status DeleteFile(const std::string& fname); + + virtual Status CreateDir(const std::string& dirname); + + virtual Status DeleteDir(const std::string& dirname); + + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size); + + virtual Status RenameFile(const std::string& src, + const std::string& target); + + virtual Status LockFile(const std::string& fname, FileLock** lock); + + virtual Status UnlockFile(FileLock* lock); + + virtual void Schedule( + void (*function)(void* arg), + void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* path); + + //virtual void Logv(WritableFile* log, const char* format, va_list ap); + + virtual Status NewLogger(const std::string& fname, Logger** result); + + virtual uint64_t NowMicros(); + + virtual void SleepForMicroseconds(int micros); +}; + +void ToWidePath(const std::string& value, std::wstring& target) { + wchar_t buffer[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); + target = buffer; +} + +void ToNarrowPath(const std::wstring& value, std::string& target) { + char buffer[MAX_PATH]; + WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); + target = buffer; +} + +std::string GetCurrentDir() +{ + CHAR path[MAX_PATH]; + ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); + *strrchr(path,'\\') = 0; + return std::string(path); +} + +std::wstring GetCurrentDirW() +{ + WCHAR path[MAX_PATH]; + ::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH); + *wcsrchr(path,L'\\') = 0; + return std::wstring(path); +} + +std::string& ModifyPath(std::string& path) +{ + if(path[0] == '/' || path[0] == '\\'){ + path = CurrentDir + path; + } + std::replace(path.begin(),path.end(),'/','\\'); + + return path; +} + +std::wstring& ModifyPath(std::wstring& path) +{ + if(path[0] == L'/' || path[0] == L'\\'){ + path = CurrentDirW + path; + } + std::replace(path.begin(),path.end(),L'/',L'\\'); + return path; +} + +std::string GetLastErrSz() +{ + LPWSTR lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + std::string Err; + ToNarrowPath(lpMsgBuf, Err); + LocalFree( lpMsgBuf ); + return Err; +} + +std::wstring GetLastErrSzW() +{ + LPVOID lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + std::wstring Err = (LPCWSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + return Err; +} + +WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) : + proc(proc_),pContent(content_) +{ + +} + +DWORD WINAPI WorkItemWrapperProc(LPVOID pContent) +{ + WorkItemWrapper* item = static_cast(pContent); + ScheduleProc TempProc = item->proc; + void* arg = item->pContent; + delete item; + TempProc(arg); + return 0; +} + +size_t GetPageSize() +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return std::max(si.dwPageSize,si.dwAllocationGranularity); +} + +const size_t g_PageSize = GetPageSize(); + + +Win32SequentialFile::Win32SequentialFile( const std::string& fname ) : + _filename(fname),_hFile(NULL) +{ + _Init(); +} + +Win32SequentialFile::~Win32SequentialFile() +{ + _CleanUp(); +} + +Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch ) +{ + Status sRet; + DWORD hasRead = 0; + if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){ + *result = Slice(scratch,hasRead); + } else { + sRet = Status::IOError(_filename, Win32::GetLastErrSz() ); + } + return sRet; +} + +Status Win32SequentialFile::Skip( uint64_t n ) +{ + Status sRet; + LARGE_INTEGER Move,NowPointer; + Move.QuadPart = n; + if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){ + sRet = Status::IOError(_filename,Win32::GetLastErrSz()); + } + return sRet; +} + +BOOL Win32SequentialFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +BOOL Win32SequentialFile::_Init() +{ + std::wstring path; + ToWidePath(_filename, path); + _hFile = CreateFileW(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + return _hFile ? TRUE : FALSE; +} + +void Win32SequentialFile::_CleanUp() +{ + if(_hFile){ + CloseHandle(_hFile); + _hFile = NULL; + } +} + +Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) : + _filename(fname),_hFile(NULL) +{ + std::wstring path; + ToWidePath(fname, path); + _Init( path.c_str() ); +} + +Win32RandomAccessFile::~Win32RandomAccessFile() +{ + _CleanUp(); +} + +Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const +{ + Status sRet; + OVERLAPPED ol = {0}; + ZeroMemory(&ol,sizeof(ol)); + ol.Offset = (DWORD)offset; + ol.OffsetHigh = (DWORD)(offset >> 32); + DWORD hasRead = 0; + if(!ReadFile(_hFile,scratch,n,&hasRead,&ol)) + sRet = Status::IOError(_filename,Win32::GetLastErrSz()); + else + *result = Slice(scratch,hasRead); + return sRet; +} + +BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) +{ + BOOL bRet = FALSE; + if(!_hFile) + _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) + _hFile = NULL; + else + bRet = TRUE; + return bRet; +} + +BOOL Win32RandomAccessFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +void Win32RandomAccessFile::_CleanUp() +{ + if(_hFile){ + ::CloseHandle(_hFile); + _hFile = NULL; + } +} + +size_t Win32MapFile::_Roundup( size_t x, size_t y ) +{ + return ((x + y - 1) / y) * y; +} + +size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) +{ + s -= (s & (_page_size - 1)); + assert((s % _page_size) == 0); + return s; +} + +bool Win32MapFile::_UnmapCurrentRegion() +{ + bool result = true; + if (_base != NULL) { + if (_last_sync < _limit) { + // Defer syncing this data until next Sync() call, if any + _pending_sync = true; + } + if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) + result = false; + _file_offset += _limit - _base; + _base = NULL; + _base_handle = NULL; + _limit = NULL; + _last_sync = NULL; + _dst = NULL; + // Increase the amount we map the next time, but capped at 1MB + if (_map_size < (1<<20)) { + _map_size *= 2; + } + } + return result; +} + +bool Win32MapFile::_MapNewRegion() +{ + assert(_base == NULL); + //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); + //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); + DWORD off_hi = (DWORD)(_file_offset >> 32); + DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); + LARGE_INTEGER newSize; + newSize.QuadPart = _file_offset + _map_size; + SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); + SetEndOfFile(_hFile); + + _base_handle = CreateFileMappingA( + _hFile, + NULL, + PAGE_READWRITE, + 0, + 0, + 0); + if (_base_handle != NULL) { + _base = (char*) MapViewOfFile(_base_handle, + FILE_MAP_ALL_ACCESS, + off_hi, + off_lo, + _map_size); + if (_base != NULL) { + _limit = _base + _map_size; + _dst = _base; + _last_sync = _base; + return true; + } + } + return false; +} + +Win32MapFile::Win32MapFile( const std::string& fname) : + _filename(fname), + _hFile(NULL), + _page_size(Win32::g_PageSize), + _map_size(_Roundup(65536, Win32::g_PageSize)), + _base(NULL), + _base_handle(NULL), + _limit(NULL), + _dst(NULL), + _last_sync(NULL), + _file_offset(0), + _pending_sync(false) +{ + std::wstring path; + ToWidePath(fname, path); + _Init(path.c_str()); + assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); +} + +Status Win32MapFile::Append( const Slice& data ) +{ + const char* src = data.data(); + size_t left = data.size(); + Status s; + while (left > 0) { + assert(_base <= _dst); + assert(_dst <= _limit); + size_t avail = _limit - _dst; + if (avail == 0) { + if (!_UnmapCurrentRegion() || + !_MapNewRegion()) { + return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); + } + } + size_t n = (left <= avail) ? left : avail; + memcpy(_dst, src, n); + _dst += n; + src += n; + left -= n; + } + return s; +} + +Status Win32MapFile::Close() +{ + Status s; + size_t unused = _limit - _dst; + if (!_UnmapCurrentRegion()) { + s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); + } else if (unused > 0) { + // Trim the extra space at the end of the file + LARGE_INTEGER newSize; + newSize.QuadPart = _file_offset - unused; + if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { + s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); + } else + SetEndOfFile(_hFile); + } + if (!CloseHandle(_hFile)) { + if (s.ok()) { + s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); + } + } + _hFile = INVALID_HANDLE_VALUE; + _base = NULL; + _base_handle = NULL; + _limit = NULL; + + return s; +} + +Status Win32MapFile::Sync() +{ + Status s; + if (_pending_sync) { + // Some unmapped data was not synced + _pending_sync = false; + if (!FlushFileBuffers(_hFile)) { + s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); + } + } + if (_dst > _last_sync) { + // Find the beginnings of the pages that contain the first and last + // bytes to be synced. + size_t p1 = _TruncateToPageBoundary(_last_sync - _base); + size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); + _last_sync = _dst; + if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { + s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); + } + } + return s; +} + +Status Win32MapFile::Flush() +{ + return Status::OK(); +} + +Win32MapFile::~Win32MapFile() +{ + if (_hFile != INVALID_HANDLE_VALUE) { + Win32MapFile::Close(); + } +} + +BOOL Win32MapFile::_Init( LPCWSTR Path ) +{ + DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; + _hFile = CreateFileW(Path, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, + NULL, + Flag, + FILE_ATTRIBUTE_NORMAL, + NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE) + return FALSE; + else + return TRUE; +} + +BOOL Win32MapFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +Win32FileLock::Win32FileLock( const std::string& fname ) : + _hFile(NULL),_filename(fname) +{ + std::wstring path; + ToWidePath(fname, path); + _Init(path.c_str()); +} + +Win32FileLock::~Win32FileLock() +{ + _CleanUp(); +} + +BOOL Win32FileLock::_Init( LPCWSTR path ) +{ + BOOL bRet = FALSE; + if(!_hFile) + _hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){ + _hFile = NULL; + } + else + bRet = TRUE; + return bRet; +} + +void Win32FileLock::_CleanUp() +{ + ::CloseHandle(_hFile); + _hFile = NULL; +} + +BOOL Win32FileLock::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile) +{ + assert(_pFileProxy); +} + +Win32Logger::~Win32Logger() +{ + if(_pFileProxy) + delete _pFileProxy; +} + +void Win32Logger::Logv( const char* format, va_list ap ) +{ + uint64_t thread_id = ::GetCurrentThreadId(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + 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; + + SYSTEMTIME st; + GetLocalTime(&st); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + int(st.wYear), + int(st.wMonth), + int(st.wDay), + int(st.wHour), + int(st.wMinute), + int(st.wMinute), + int(st.wMilliseconds), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + 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); + DWORD hasWritten = 0; + if(_pFileProxy){ + _pFileProxy->Append(Slice(base, p - base)); + _pFileProxy->Flush(); + } + if (base != buffer) { + delete[] base; + } + break; + } +} + +bool Win32Env::FileExists(const std::string& fname) +{ + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + return ::PathFileExistsW(wpath.c_str()) ? true : false; +} + +Status Win32Env::GetChildren(const std::string& dir, std::vector* result) +{ + Status sRet; + ::WIN32_FIND_DATAW wfd; + std::string path = dir; + ModifyPath(path); + path += "\\*.*"; + std::wstring wpath; + ToWidePath(path, wpath); + + ::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd); + if(hFind && hFind != INVALID_HANDLE_VALUE){ + BOOL hasNext = TRUE; + std::string child; + while(hasNext){ + ToNarrowPath(wfd.cFileName, child); + if(child != ".." && child != ".") { + result->push_back(child); + } + hasNext = ::FindNextFileW(hFind,&wfd); + } + ::FindClose(hFind); + } + else + sRet = Status::IOError(dir,"Could not get children."); + return sRet; +} + +void Win32Env::SleepForMicroseconds( int micros ) +{ + ::Sleep((micros + 999) /1000); +} + + +Status Win32Env::DeleteFile( const std::string& fname ) +{ + Status sRet; + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + + if(!::DeleteFileW(wpath.c_str())) { + sRet = Status::IOError(path, "Could not delete file."); + } + return sRet; +} + +Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) +{ + Status sRet; + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + + HANDLE file = ::CreateFileW(wpath.c_str(), + GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + LARGE_INTEGER li; + if(::GetFileSizeEx(file,&li)){ + *file_size = (uint64_t)li.QuadPart; + }else + sRet = Status::IOError(path,"Could not get the file size."); + CloseHandle(file); + return sRet; +} + +Status Win32Env::RenameFile( const std::string& src, const std::string& target ) +{ + Status sRet; + std::string src_path = src; + std::wstring wsrc_path; + ToWidePath(ModifyPath(src_path), wsrc_path); + std::string target_path = target; + std::wstring wtarget_path; + ToWidePath(ModifyPath(target_path), wtarget_path); + + if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){ + DWORD err = GetLastError(); + if(err == 0x000000b7){ + if(!::DeleteFileW(wtarget_path.c_str() ) ) + sRet = Status::IOError(src, "Could not rename file."); + else if(!::MoveFileW(wsrc_path.c_str(), + wtarget_path.c_str() ) ) + sRet = Status::IOError(src, "Could not rename file."); + } + } + return sRet; +} + +Status Win32Env::LockFile( const std::string& fname, FileLock** lock ) +{ + Status sRet; + std::string path = fname; + ModifyPath(path); + Win32FileLock* _lock = new Win32FileLock(path); + if(!_lock->isEnable()){ + delete _lock; + *lock = NULL; + sRet = Status::IOError(path, "Could not lock file."); + } + else + *lock = _lock; + return sRet; +} + +Status Win32Env::UnlockFile( FileLock* lock ) +{ + Status sRet; + delete lock; + return sRet; +} + +void Win32Env::Schedule( void (*function)(void* arg), void* arg ) +{ + QueueUserWorkItem(Win32::WorkItemWrapperProc, + new Win32::WorkItemWrapper(function,arg), + WT_EXECUTEDEFAULT); +} + +void Win32Env::StartThread( void (*function)(void* arg), void* arg ) +{ + ::_beginthread(function,0,arg); +} + +Status Win32Env::GetTestDirectory( std::string* path ) +{ + Status sRet; + WCHAR TempPath[MAX_PATH]; + ::GetTempPathW(MAX_PATH,TempPath); + ToNarrowPath(TempPath, *path); + path->append("leveldb\\test\\"); + ModifyPath(*path); + return sRet; +} + +uint64_t Win32Env::NowMicros() +{ +#ifndef USE_VISTA_API +#define GetTickCount64 GetTickCount +#endif + return (uint64_t)(GetTickCount64()*1000); +} + +static Status CreateDirInner( const std::string& dirname ) +{ + Status sRet; + DWORD attr = ::GetFileAttributes(dirname.c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: + std::size_t slash = dirname.find_last_of("\\"); + if (slash != std::string::npos){ + sRet = CreateDirInner(dirname.substr(0, slash)); + if (!sRet.ok()) return sRet; + } + BOOL result = ::CreateDirectory(dirname.c_str(), NULL); + if (result == FALSE) { + sRet = Status::IOError(dirname, "Could not create directory."); + return sRet; + } + } + return sRet; +} + +Status Win32Env::CreateDir( const std::string& dirname ) +{ + std::string path = dirname; + if(path[path.length() - 1] != '\\'){ + path += '\\'; + } + ModifyPath(path); + + return CreateDirInner(path); +} + +Status Win32Env::DeleteDir( const std::string& dirname ) +{ + Status sRet; + std::wstring path; + ToWidePath(dirname, path); + ModifyPath(path); + if(!::RemoveDirectoryW( path.c_str() ) ){ + sRet = Status::IOError(dirname, "Could not delete directory."); + } + return sRet; +} + +Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result ) +{ + Status sRet; + std::string path = fname; + ModifyPath(path); + Win32SequentialFile* pFile = new Win32SequentialFile(path); + if(pFile->isEnable()){ + *result = pFile; + }else { + delete pFile; + sRet = Status::IOError(path, Win32::GetLastErrSz()); + } + return sRet; +} + +Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result ) +{ + Status sRet; + std::string path = fname; + Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path)); + if(!pFile->isEnable()){ + delete pFile; + *result = NULL; + sRet = Status::IOError(path, Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Status Win32Env::NewLogger( const std::string& fname, Logger** result ) +{ + Status sRet; + std::string path = fname; + Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); + if(!pMapFile->isEnable()){ + delete pMapFile; + *result = NULL; + sRet = Status::IOError(path,"could not create a logger."); + }else + *result = new Win32Logger(pMapFile); + return sRet; +} + +Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result ) +{ + Status sRet; + std::string path = fname; + Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); + if(!pFile->isEnable()){ + *result = NULL; + sRet = Status::IOError(fname,Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Win32Env::Win32Env() +{ + +} + +Win32Env::~Win32Env() +{ + +} + + +} // Win32 namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new Win32::Win32Env(); } + +Env* Env::Default() { + port::InitOnce(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#endif // defined(LEVELDB_PLATFORM_WINDOWS) diff --git a/src/leveldb/util/filter_policy.cc b/src/leveldb/util/filter_policy.cc new file mode 100644 index 0000000..7b045c8 --- /dev/null +++ b/src/leveldb/util/filter_policy.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +namespace leveldb { + +FilterPolicy::~FilterPolicy() { } + +} // namespace leveldb diff --git a/src/leveldb/util/hash.cc b/src/leveldb/util/hash.cc new file mode 100644 index 0000000..07cf022 --- /dev/null +++ b/src/leveldb/util/hash.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "util/coding.h" +#include "util/hash.h" + +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels. The real definition should be provided externally. +// This one is a fallback version for unsupported compilers. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED do { } while (0) +#endif + +namespace leveldb { + +uint32_t Hash(const char* data, size_t n, uint32_t seed) { + // Similar to murmur hash + const uint32_t m = 0xc6a4a793; + const uint32_t r = 24; + const char* limit = data + n; + uint32_t h = seed ^ (n * m); + + // Pick up four bytes at a time + while (data + 4 <= limit) { + uint32_t w = DecodeFixed32(data); + data += 4; + h += w; + h *= m; + h ^= (h >> 16); + } + + // Pick up remaining bytes + switch (limit - data) { + case 3: + h += data[2] << 16; + FALLTHROUGH_INTENDED; + case 2: + h += data[1] << 8; + FALLTHROUGH_INTENDED; + case 1: + h += data[0]; + h *= m; + h ^= (h >> r); + break; + } + return h; +} + + +} // namespace leveldb diff --git a/src/leveldb/util/hash.h b/src/leveldb/util/hash.h new file mode 100644 index 0000000..8889d56 --- /dev/null +++ b/src/leveldb/util/hash.h @@ -0,0 +1,19 @@ +// 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. +// +// Simple hash function used for internal data structures + +#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ +#define STORAGE_LEVELDB_UTIL_HASH_H_ + +#include +#include + +namespace leveldb { + +extern uint32_t Hash(const char* data, size_t n, uint32_t seed); + +} + +#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/src/leveldb/util/histogram.cc b/src/leveldb/util/histogram.cc new file mode 100644 index 0000000..bb95f58 --- /dev/null +++ b/src/leveldb/util/histogram.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "port/port.h" +#include "util/histogram.h" + +namespace leveldb { + +const double Histogram::kBucketLimit[kNumBuckets] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, + 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450, + 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, + 16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000, + 70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000, + 250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000, + 900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000, + 3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000, + 9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000, + 25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000, + 70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000, + 180000000, 200000000, 250000000, 300000000, 350000000, 400000000, + 450000000, 500000000, 600000000, 700000000, 800000000, 900000000, + 1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000, + 2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0, + 5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0, + 1e200, +}; + +void Histogram::Clear() { + min_ = kBucketLimit[kNumBuckets-1]; + max_ = 0; + num_ = 0; + sum_ = 0; + sum_squares_ = 0; + for (int i = 0; i < kNumBuckets; i++) { + buckets_[i] = 0; + } +} + +void Histogram::Add(double value) { + // Linear search is fast enough for our usage in db_bench + int b = 0; + while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { + b++; + } + buckets_[b] += 1.0; + if (min_ > value) min_ = value; + if (max_ < value) max_ = value; + num_++; + sum_ += value; + sum_squares_ += (value * value); +} + +void Histogram::Merge(const Histogram& other) { + if (other.min_ < min_) min_ = other.min_; + if (other.max_ > max_) max_ = other.max_; + num_ += other.num_; + sum_ += other.sum_; + sum_squares_ += other.sum_squares_; + for (int b = 0; b < kNumBuckets; b++) { + buckets_[b] += other.buckets_[b]; + } +} + +double Histogram::Median() const { + return Percentile(50.0); +} + +double Histogram::Percentile(double p) const { + double threshold = num_ * (p / 100.0); + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + sum += buckets_[b]; + if (sum >= threshold) { + // Scale linearly within this bucket + double left_point = (b == 0) ? 0 : kBucketLimit[b-1]; + double right_point = kBucketLimit[b]; + double left_sum = sum - buckets_[b]; + double right_sum = sum; + double pos = (threshold - left_sum) / (right_sum - left_sum); + double r = left_point + (right_point - left_point) * pos; + if (r < min_) r = min_; + if (r > max_) r = max_; + return r; + } + } + return max_; +} + +double Histogram::Average() const { + if (num_ == 0.0) return 0; + return sum_ / num_; +} + +double Histogram::StandardDeviation() const { + if (num_ == 0.0) return 0; + double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); + return sqrt(variance); +} + +std::string Histogram::ToString() const { + std::string r; + char buf[200]; + snprintf(buf, sizeof(buf), + "Count: %.0f Average: %.4f StdDev: %.2f\n", + num_, Average(), StandardDeviation()); + r.append(buf); + snprintf(buf, sizeof(buf), + "Min: %.4f Median: %.4f Max: %.4f\n", + (num_ == 0.0 ? 0.0 : min_), Median(), max_); + r.append(buf); + r.append("------------------------------------------------------\n"); + const double mult = 100.0 / num_; + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + if (buckets_[b] <= 0.0) continue; + sum += buckets_[b]; + snprintf(buf, sizeof(buf), + "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", + ((b == 0) ? 0.0 : kBucketLimit[b-1]), // left + kBucketLimit[b], // right + buckets_[b], // count + mult * buckets_[b], // percentage + mult * sum); // cumulative percentage + r.append(buf); + + // Add hash marks based on percentage; 20 marks for 100%. + int marks = static_cast(20*(buckets_[b] / num_) + 0.5); + r.append(marks, '#'); + r.push_back('\n'); + } + return r; +} + +} // namespace leveldb diff --git a/src/leveldb/util/histogram.h b/src/leveldb/util/histogram.h new file mode 100644 index 0000000..1ef9f3c --- /dev/null +++ b/src/leveldb/util/histogram.h @@ -0,0 +1,42 @@ +// 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_UTIL_HISTOGRAM_H_ +#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ + +#include + +namespace leveldb { + +class Histogram { + public: + Histogram() { } + ~Histogram() { } + + void Clear(); + void Add(double value); + void Merge(const Histogram& other); + + std::string ToString() const; + + private: + double min_; + double max_; + double num_; + double sum_; + double sum_squares_; + + enum { kNumBuckets = 154 }; + static const double kBucketLimit[kNumBuckets]; + double buckets_[kNumBuckets]; + + double Median() const; + double Percentile(double p) const; + double Average() const; + double StandardDeviation() const; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc new file mode 100644 index 0000000..22cf278 --- /dev/null +++ b/src/leveldb/util/logging.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/logging.h" + +#include +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" + +namespace leveldb { + +void AppendNumberTo(std::string* str, uint64_t num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num); + str->append(buf); +} + +void AppendEscapedStringTo(std::string* str, const Slice& value) { + for (size_t i = 0; i < value.size(); i++) { + char c = value[i]; + if (c >= ' ' && c <= '~') { + str->push_back(c); + } else { + char buf[10]; + snprintf(buf, sizeof(buf), "\\x%02x", + static_cast(c) & 0xff); + str->append(buf); + } + } +} + +std::string NumberToString(uint64_t num) { + std::string r; + AppendNumberTo(&r, num); + return r; +} + +std::string EscapeString(const Slice& value) { + std::string r; + AppendEscapedStringTo(&r, value); + return r; +} + +bool ConsumeChar(Slice* in, char c) { + if (!in->empty() && (*in)[0] == c) { + in->remove_prefix(1); + return true; + } else { + return false; + } +} + +bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { + uint64_t v = 0; + int digits = 0; + while (!in->empty()) { + char c = (*in)[0]; + if (c >= '0' && c <= '9') { + ++digits; + const int delta = (c - '0'); + static const uint64_t kMaxUint64 = ~static_cast(0); + if (v > kMaxUint64/10 || + (v == kMaxUint64/10 && delta > kMaxUint64%10)) { + // Overflow + return false; + } + v = (v * 10) + delta; + in->remove_prefix(1); + } else { + break; + } + } + *val = v; + return (digits > 0); +} + +} // namespace leveldb diff --git a/src/leveldb/util/logging.h b/src/leveldb/util/logging.h new file mode 100644 index 0000000..b0c5da8 --- /dev/null +++ b/src/leveldb/util/logging.h @@ -0,0 +1,47 @@ +// 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. +// +// Must not be included from any .h files to avoid polluting the namespace +// with macros. + +#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ +#define STORAGE_LEVELDB_UTIL_LOGGING_H_ + +#include +#include +#include +#include "port/port.h" + +namespace leveldb { + +class Slice; +class WritableFile; + +// Append a human-readable printout of "num" to *str +extern void AppendNumberTo(std::string* str, uint64_t num); + +// Append a human-readable printout of "value" to *str. +// Escapes any non-printable characters found in "value". +extern void AppendEscapedStringTo(std::string* str, const Slice& value); + +// Return a human-readable printout of "num" +extern std::string NumberToString(uint64_t num); + +// Return a human-readable version of "value". +// Escapes any non-printable characters found in "value". +extern std::string EscapeString(const Slice& value); + +// If *in starts with "c", advances *in past the first character and +// returns true. Otherwise, returns false. +extern bool ConsumeChar(Slice* in, char c); + +// Parse a human-readable number from "*in" into *value. On success, +// advances "*in" past the consumed number and sets "*val" to the +// numeric value. Otherwise, returns false and leaves *in in an +// unspecified state. +extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/src/leveldb/util/mutexlock.h b/src/leveldb/util/mutexlock.h new file mode 100644 index 0000000..1ff5a9e --- /dev/null +++ b/src/leveldb/util/mutexlock.h @@ -0,0 +1,41 @@ +// 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_UTIL_MUTEXLOCK_H_ +#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ + +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +// Helper class that locks a mutex on construction and unlocks the mutex when +// the destructor of the MutexLock object is invoked. +// +// Typical usage: +// +// void MyClass::MyMethod() { +// MutexLock l(&mu_); // mu_ is an instance variable +// ... some complex code, possibly with multiple return paths ... +// } + +class SCOPED_LOCKABLE MutexLock { + public: + explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) + : mu_(mu) { + this->mu_->Lock(); + } + ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } + + private: + port::Mutex *const mu_; + // No copying allowed + MutexLock(const MutexLock&); + void operator=(const MutexLock&); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/src/leveldb/util/options.cc b/src/leveldb/util/options.cc new file mode 100644 index 0000000..76af5b9 --- /dev/null +++ b/src/leveldb/util/options.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/options.h" + +#include "leveldb/comparator.h" +#include "leveldb/env.h" + +namespace leveldb { + +Options::Options() + : comparator(BytewiseComparator()), + create_if_missing(false), + error_if_exists(false), + paranoid_checks(false), + env(Env::Default()), + info_log(NULL), + write_buffer_size(4<<20), + max_open_files(1000), + block_cache(NULL), + block_size(4096), + block_restart_interval(16), + compression(kSnappyCompression), + filter_policy(NULL) { +} + + +} // namespace leveldb diff --git a/src/leveldb/util/posix_logger.h b/src/leveldb/util/posix_logger.h new file mode 100644 index 0000000..c063c2b --- /dev/null +++ b/src/leveldb/util/posix_logger.h @@ -0,0 +1,98 @@ +// 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. +// +// Logger implementation that can be shared by all environments +// where enough Posix functionality is available. + +#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ + +#include +#include +#include +#include +#include "leveldb/env.h" + +namespace leveldb { + +class PosixLogger : public Logger { + private: + FILE* file_; + uint64_t (*gettid_)(); // Return the thread id for the current thread + public: + PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } + virtual ~PosixLogger() { + fclose(file_); + } + virtual void Logv(const char* format, va_list ap) { + const uint64_t thread_id = (*gettid_)(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + 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; + + struct timeval now_tv; + gettimeofday(&now_tv, NULL); + const time_t seconds = now_tv.tv_sec; + struct tm t; + localtime_r(&seconds, &t); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + t.tm_year + 1900, + t.tm_mon + 1, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + static_cast(now_tv.tv_usec), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + 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); + fwrite(base, 1, p - base, file_); + fflush(file_); + if (base != buffer) { + delete[] base; + } + break; + } + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/src/leveldb/util/random.h b/src/leveldb/util/random.h new file mode 100644 index 0000000..ddd51b1 --- /dev/null +++ b/src/leveldb/util/random.h @@ -0,0 +1,64 @@ +// 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_UTIL_RANDOM_H_ +#define STORAGE_LEVELDB_UTIL_RANDOM_H_ + +#include + +namespace leveldb { + +// A very simple random number generator. Not especially good at +// generating truly random bits, but good enough for our needs in this +// package. +class Random { + private: + uint32_t seed_; + public: + explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { + // Avoid bad seeds. + if (seed_ == 0 || seed_ == 2147483647L) { + seed_ = 1; + } + } + uint32_t Next() { + static const uint32_t M = 2147483647L; // 2^31-1 + static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 + // We are computing + // seed_ = (seed_ * A) % M, where M = 2^31-1 + // + // seed_ must not be zero or M, or else all subsequent computed values + // will be zero or M respectively. For all other values, seed_ will end + // up cycling through every number in [1,M-1] + uint64_t product = seed_ * A; + + // Compute (product % M) using the fact that ((x << 31) % M) == x. + seed_ = static_cast((product >> 31) + (product & M)); + // The first reduction may overflow by 1 bit, so we may need to + // repeat. mod == M is not possible; using > allows the faster + // sign-bit-based test. + if (seed_ > M) { + seed_ -= M; + } + return seed_; + } + // Returns a uniformly distributed value in the range [0..n-1] + // REQUIRES: n > 0 + uint32_t Uniform(int n) { return Next() % n; } + + // Randomly returns true ~"1/n" of the time, and false otherwise. + // REQUIRES: n > 0 + bool OneIn(int n) { return (Next() % n) == 0; } + + // Skewed: pick "base" uniformly from range [0,max_log] and then + // return "base" random bits. The effect is to pick a number in the + // range [0,2^max_log-1] with exponential bias towards smaller numbers. + uint32_t Skewed(int max_log) { + return Uniform(1 << Uniform(max_log + 1)); + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/src/leveldb/util/status.cc b/src/leveldb/util/status.cc new file mode 100644 index 0000000..a44f35b --- /dev/null +++ b/src/leveldb/util/status.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "port/port.h" +#include "leveldb/status.h" + +namespace leveldb { + +const char* Status::CopyState(const char* state) { + uint32_t size; + memcpy(&size, state, sizeof(size)); + char* result = new char[size + 5]; + memcpy(result, state, size + 5); + return result; +} + +Status::Status(Code code, const Slice& msg, const Slice& msg2) { + assert(code != kOk); + const uint32_t len1 = msg.size(); + const uint32_t len2 = msg2.size(); + const uint32_t size = len1 + (len2 ? (2 + len2) : 0); + char* result = new char[size + 5]; + memcpy(result, &size, sizeof(size)); + result[4] = static_cast(code); + memcpy(result + 5, msg.data(), len1); + if (len2) { + result[5 + len1] = ':'; + result[6 + len1] = ' '; + memcpy(result + 7 + len1, msg2.data(), len2); + } + state_ = result; +} + +std::string Status::ToString() const { + if (state_ == NULL) { + return "OK"; + } else { + char tmp[30]; + const char* type; + switch (code()) { + case kOk: + type = "OK"; + break; + case kNotFound: + type = "NotFound: "; + break; + case kCorruption: + type = "Corruption: "; + break; + case kNotSupported: + type = "Not implemented: "; + break; + case kInvalidArgument: + type = "Invalid argument: "; + break; + case kIOError: + type = "IO error: "; + break; + default: + snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", + static_cast(code())); + type = tmp; + break; + } + std::string result(type); + uint32_t length; + memcpy(&length, state_, sizeof(length)); + result.append(state_ + 5, length); + return result; + } +} + +} // namespace leveldb diff --git a/src/leveldb/util/testharness.cc b/src/leveldb/util/testharness.cc new file mode 100644 index 0000000..eb1bdd5 --- /dev/null +++ b/src/leveldb/util/testharness.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testharness.h" + +#include +#include +#include +#include + +namespace leveldb { +namespace test { + +namespace { +struct Test { + const char* base; + const char* name; + void (*func)(); +}; +std::vector* tests; +} + +bool RegisterTest(const char* base, const char* name, void (*func)()) { + if (tests == NULL) { + tests = new std::vector; + } + Test t; + t.base = base; + t.name = name; + t.func = func; + tests->push_back(t); + return true; +} + +int RunAllTests() { + const char* matcher = getenv("LEVELDB_TESTS"); + + int num = 0; + if (tests != NULL) { + for (int i = 0; i < tests->size(); i++) { + const Test& t = (*tests)[i]; + if (matcher != NULL) { + std::string name = t.base; + name.push_back('.'); + name.append(t.name); + if (strstr(name.c_str(), matcher) == NULL) { + continue; + } + } + fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); + (*t.func)(); + ++num; + } + } + fprintf(stderr, "==== PASSED %d tests\n", num); + return 0; +} + +std::string TmpDir() { + std::string dir; + Status s = Env::Default()->GetTestDirectory(&dir); + ASSERT_TRUE(s.ok()) << s.ToString(); + return dir; +} + +int RandomSeed() { + const char* env = getenv("TEST_RANDOM_SEED"); + int result = (env != NULL ? atoi(env) : 301); + if (result <= 0) { + result = 301; + } + return result; +} + +} // namespace test +} // namespace leveldb diff --git a/src/leveldb/util/testharness.h b/src/leveldb/util/testharness.h new file mode 100644 index 0000000..da4fe68 --- /dev/null +++ b/src/leveldb/util/testharness.h @@ -0,0 +1,138 @@ +// 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_UTIL_TESTHARNESS_H_ +#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ + +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Run some of the tests registered by the TEST() macro. If the +// environment variable "LEVELDB_TESTS" is not set, runs all tests. +// Otherwise, runs only the tests whose name contains the value of +// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: +// TEST(Foo, Hello) { ... } +// TEST(Foo, World) { ... } +// LEVELDB_TESTS=Hello will run the first test +// LEVELDB_TESTS=o will run both tests +// LEVELDB_TESTS=Junk will run no tests +// +// Returns 0 if all tests pass. +// Dies or returns a non-zero value if some test fails. +extern int RunAllTests(); + +// Return the directory to use for temporary storage. +extern std::string TmpDir(); + +// Return a randomization seed for this run. Typically returns the +// same number on repeated invocations of this binary, but automated +// runs may be able to vary the seed. +extern int RandomSeed(); + +// An instance of Tester is allocated to hold temporary state during +// the execution of an assertion. +class Tester { + private: + bool ok_; + const char* fname_; + int line_; + std::stringstream ss_; + + public: + Tester(const char* f, int l) + : ok_(true), fname_(f), line_(l) { + } + + ~Tester() { + if (!ok_) { + fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); + exit(1); + } + } + + Tester& Is(bool b, const char* msg) { + if (!b) { + ss_ << " Assertion failure " << msg; + ok_ = false; + } + return *this; + } + + Tester& IsOk(const Status& s) { + if (!s.ok()) { + ss_ << " " << s.ToString(); + ok_ = false; + } + return *this; + } + +#define BINARY_OP(name,op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (! (x op y)) { \ + ss_ << " failed: " << x << (" " #op " ") << y; \ + ok_ = false; \ + } \ + return *this; \ + } + + BINARY_OP(IsEq, ==) + BINARY_OP(IsNe, !=) + BINARY_OP(IsGe, >=) + BINARY_OP(IsGt, >) + BINARY_OP(IsLe, <=) + BINARY_OP(IsLt, <) +#undef BINARY_OP + + // Attach the specified value to the error message if an error has occurred + template + Tester& operator<<(const V& value) { + if (!ok_) { + ss_ << " " << value; + } + return *this; + } +}; + +#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) +#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) +#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) +#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) +#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) +#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) +#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) +#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) + +#define TCONCAT(a,b) TCONCAT1(a,b) +#define TCONCAT1(a,b) a##b + +#define TEST(base,name) \ +class TCONCAT(_Test_,name) : public base { \ + public: \ + void _Run(); \ + static void _RunIt() { \ + TCONCAT(_Test_,name) t; \ + t._Run(); \ + } \ +}; \ +bool TCONCAT(_Test_ignored_,name) = \ + ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \ +void TCONCAT(_Test_,name)::_Run() + +// Register the specified test. Typically not used directly, but +// invoked via the macro expansion of TEST. +extern bool RegisterTest(const char* base, const char* name, void (*func)()); + + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/src/leveldb/util/testutil.cc b/src/leveldb/util/testutil.cc new file mode 100644 index 0000000..538d095 --- /dev/null +++ b/src/leveldb/util/testutil.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testutil.h" + +#include "util/random.h" + +namespace leveldb { +namespace test { + +Slice RandomString(Random* rnd, int len, std::string* dst) { + dst->resize(len); + for (int i = 0; i < len; i++) { + (*dst)[i] = static_cast(' ' + rnd->Uniform(95)); // ' ' .. '~' + } + return Slice(*dst); +} + +std::string RandomKey(Random* rnd, int len) { + // Make sure to generate a wide variety of characters so we + // test the boundary conditions for short-key optimizations. + static const char kTestChars[] = { + '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' + }; + std::string result; + for (int i = 0; i < len; i++) { + result += kTestChars[rnd->Uniform(sizeof(kTestChars))]; + } + return result; +} + + +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + int len, std::string* dst) { + int raw = static_cast(len * compressed_fraction); + if (raw < 1) raw = 1; + std::string raw_data; + RandomString(rnd, raw, &raw_data); + + // Duplicate the random data until we have filled "len" bytes + dst->clear(); + while (dst->size() < len) { + dst->append(raw_data); + } + dst->resize(len); + return Slice(*dst); +} + +} // namespace test +} // namespace leveldb diff --git a/src/leveldb/util/testutil.h b/src/leveldb/util/testutil.h new file mode 100644 index 0000000..824e655 --- /dev/null +++ b/src/leveldb/util/testutil.h @@ -0,0 +1,53 @@ +// 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_UTIL_TESTUTIL_H_ +#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ + +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Store in *dst a random string of length "len" and return a Slice that +// references the generated data. +extern Slice RandomString(Random* rnd, int len, std::string* dst); + +// Return a random key with the specified length that may contain interesting +// characters (e.g. \x00, \xff, etc.). +extern std::string RandomKey(Random* rnd, int len); + +// Store in *dst a string of length "len" that will compress to +// "N*compressed_fraction" bytes and return a Slice that references +// the generated data. +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + int len, std::string* dst); + +// A wrapper that allows injection of errors. +class ErrorEnv : public EnvWrapper { + public: + bool writable_file_error_; + int num_writable_file_errors_; + + ErrorEnv() : EnvWrapper(Env::Default()), + writable_file_error_(false), + num_writable_file_errors_(0) { } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = NULL; + return Status::IOError(fname, "fake error"); + } + return target()->NewWritableFile(fname, result); + } +}; + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ diff --git a/src/limitedmap.h b/src/limitedmap.h new file mode 100644 index 0000000..7049d68 --- /dev/null +++ b/src/limitedmap.h @@ -0,0 +1,100 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_LIMITEDMAP_H +#define BITCOIN_LIMITEDMAP_H + +#include +#include + +/** STL-like map container that only keeps the N elements with the highest value. */ +template class limitedmap +{ +public: + typedef K key_type; + typedef V mapped_type; + typedef std::pair value_type; + typedef typename std::map::const_iterator const_iterator; + typedef typename std::map::size_type size_type; + +protected: + std::map map; + typedef typename std::map::iterator iterator; + std::multimap rmap; + typedef typename std::multimap::iterator rmap_iterator; + size_type nMaxSize; + +public: + limitedmap(size_type nMaxSizeIn = 0) { nMaxSize = nMaxSizeIn; } + const_iterator begin() const { return map.begin(); } + const_iterator end() const { return map.end(); } + size_type size() const { return map.size(); } + bool empty() const { return map.empty(); } + const_iterator find(const key_type& k) const { return map.find(k); } + size_type count(const key_type& k) const { return map.count(k); } + void insert(const value_type& x) + { + std::pair ret = map.insert(x); + if (ret.second) + { + if (nMaxSize && map.size() == nMaxSize) + { + map.erase(rmap.begin()->second); + rmap.erase(rmap.begin()); + } + rmap.insert(make_pair(x.second, ret.first)); + } + return; + } + void erase(const key_type& k) + { + iterator itTarget = map.find(k); + if (itTarget == map.end()) + return; + std::pair itPair = rmap.equal_range(itTarget->second); + for (rmap_iterator it = itPair.first; it != itPair.second; ++it) + if (it->second == itTarget) + { + rmap.erase(it); + map.erase(itTarget); + return; + } + // Shouldn't ever get here + assert(0); //TODO remove me + map.erase(itTarget); + } + 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); + if (itTarget == map.end()) + return; + std::pair itPair = rmap.equal_range(itTarget->second); + for (rmap_iterator it = itPair.first; it != itPair.second; ++it) + if (it->second == itTarget) + { + rmap.erase(it); + itTarget->second = v; + rmap.insert(make_pair(v, itTarget)); + return; + } + // Shouldn't ever get here + assert(0); //TODO remove me + itTarget->second = v; + rmap.insert(make_pair(v, itTarget)); + } + size_type max_size() const { return nMaxSize; } + size_type max_size(size_type s) + { + if (s) + while (map.size() > s) + { + map.erase(rmap.begin()->second); + rmap.erase(rmap.begin()); + } + nMaxSize = s; + return nMaxSize; + } +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 83976ef..b242f6c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,18 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers +// Copyright (c) 2013-2014 Dr Kimoto Chan +// Copyright (c) 2013-2014 The CasinoCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "alert.h" #include "checkpoints.h" #include "db.h" +#include "txdb.h" #include "net.h" #include "init.h" #include "ui_interface.h" +#include "checkqueue.h" #include #include #include @@ -34,32 +37,43 @@ uint256 hashGenesisBlock("0x4f46c9af6d88a14114b7dc53a37d81ba4064cda5ae2ede1213ca static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20); // CasinoCoin: starting difficulty is 1 / 2^12 CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; -CBigNum bnBestChainWork = 0; -CBigNum bnBestInvalidWork = 0; +uint256 nBestChainWork = 0; +uint256 nBestInvalidWork = 0; uint256 hashBestChain = 0; CBlockIndex* pindexBest = NULL; +set setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed int64 nTimeBestReceived = 0; +int nScriptCheckThreads = 0; +bool fImporting = false; +bool fReindex = false; +bool fBenchmark = false; +bool fTxIndex = false; +unsigned int nCoinCacheSize = 5000; -CMedianFilter cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have +/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ +int64 CTransaction::nMinTxFee = 100000; +/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ +int64 CTransaction::nMinRelayTxFee = 100000; + +CMedianFilter cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have map mapOrphanBlocks; multimap mapOrphanBlocksByPrev; -map mapOrphanTransactions; -map > mapOrphanTransactionsByPrev; +map mapOrphanTransactions; +map > mapOrphanTransactionsByPrev; // Constant stuff for coinbase transactions we create: CScript COINBASE_FLAGS; const string strMessageMagic = "CasinoCoin Signed Message:\n"; -double dHashesPerSec; -int64 nHPSTimerStart; +double dHashesPerSec = 0.0; +int64 nHPSTimerStart = 0; // Settings int64 nTransactionFee = 0; -int64 nMinimumInputValue = CENT / 100; - +int64 nMinimumInputValue = DUST_HARD_LIMIT; ////////////////////////////////////////////////////////////////////////////// @@ -86,15 +100,6 @@ void UnregisterWallet(CWallet* pwalletIn) } } -// check whether the passed transaction is from us -bool static IsFromMe(CTransaction& tx) -{ - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - if (pwallet->IsFromMe(tx)) - return true; - return false; -} - // get the wallet transaction with the given hash (if it exists) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) { @@ -112,10 +117,10 @@ void static EraseFromWallets(uint256 hash) } // make sure all wallets know about the given transaction, in the given block -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate) +void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); + pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate); } // notify wallets about a new best chain @@ -159,21 +164,133 @@ void static ResendWalletTransactions() +////////////////////////////////////////////////////////////////////////////// +// +// CCoinsView implementations +// + +bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } +bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } +bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } +CBlockIndex *CCoinsView::GetBestBlock() { return NULL; } +bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; } +bool CCoinsView::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { return false; } +bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } + + +CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } +bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } +bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } +bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } +CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } +bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); } +void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } +bool CCoinsViewBacked::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); } +bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } + +CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { } + +bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { + if (cacheCoins.count(txid)) { + coins = cacheCoins[txid]; + return true; + } + if (base->GetCoins(txid, coins)) { + cacheCoins[txid] = coins; + return true; + } + return false; +} + +std::map::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { + std::map::iterator it = cacheCoins.lower_bound(txid); + if (it != cacheCoins.end() && it->first == txid) + return it; + CCoins tmp; + if (!base->GetCoins(txid,tmp)) + return cacheCoins.end(); + std::map::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins())); + tmp.swap(ret->second); + return ret; +} + +CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { + std::map::iterator it = FetchCoins(txid); + assert(it != cacheCoins.end()); + return it->second; +} + +bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { + cacheCoins[txid] = coins; + return true; +} + +bool CCoinsViewCache::HaveCoins(const uint256 &txid) { + return FetchCoins(txid) != cacheCoins.end(); +} + +CBlockIndex *CCoinsViewCache::GetBestBlock() { + if (pindexTip == NULL) + pindexTip = base->GetBestBlock(); + return pindexTip; +} + +bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) { + pindexTip = pindex; + return true; +} + +bool CCoinsViewCache::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { + for (std::map::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) + cacheCoins[it->first] = it->second; + pindexTip = pindex; + return true; +} + +bool CCoinsViewCache::Flush() { + bool fOk = base->BatchWrite(cacheCoins, pindexTip); + if (fOk) + cacheCoins.clear(); + return fOk; +} + +unsigned int CCoinsViewCache::GetCacheSize() { + return cacheCoins.size(); +} + +/** CCoinsView that brings transactions from a memorypool into view. + It does not check for spendings by memory pool transactions. */ +CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } + +bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { + if (base->GetCoins(txid, coins)) + return true; + if (mempool.exists(txid)) { + const CTransaction &tx = mempool.lookup(txid); + coins = CCoins(tx, MEMPOOL_HEIGHT); + return true; + } + return false; +} + +bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) { + return mempool.exists(txid) || base->HaveCoins(txid); +} + +CCoinsViewCache *pcoinsTip = NULL; +CBlockTreeDB *pblocktree = NULL; + ////////////////////////////////////////////////////////////////////////////// // // mapOrphanTransactions // -bool AddOrphanTx(const CDataStream& vMsg) +bool AddOrphanTx(const CTransaction& tx) { - CTransaction tx; - CDataStream(vMsg) >> tx; uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) return false; - CDataStream* pvMsg = new CDataStream(vMsg); - // 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 @@ -181,18 +298,18 @@ bool AddOrphanTx(const CDataStream& vMsg) // have been mined or received. // 10,000 orphans, each of which is at most 5,000 bytes big is // at most 500 megabytes of orphans: - if (pvMsg->size() > 5000) + unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + if (sz > 5000) { - printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str()); - delete pvMsg; + printf("ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString().c_str()); return false; } - mapOrphanTransactions[hash] = pvMsg; + mapOrphanTransactions[hash] = tx; BOOST_FOREACH(const CTxIn& txin, tx.vin) - mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg)); + mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); - printf("stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10).c_str(), + printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().c_str(), mapOrphanTransactions.size()); return true; } @@ -201,16 +318,13 @@ void static EraseOrphanTx(uint256 hash) { if (!mapOrphanTransactions.count(hash)) return; - const CDataStream* pvMsg = mapOrphanTransactions[hash]; - CTransaction tx; - CDataStream(*pvMsg) >> tx; + const CTransaction& tx = mapOrphanTransactions[hash]; BOOST_FOREACH(const CTxIn& txin, tx.vin) { mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash); if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty()) mapOrphanTransactionsByPrev.erase(txin.prevout.hash); } - delete pvMsg; mapOrphanTransactions.erase(hash); } @@ -221,7 +335,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) { // Evict a random orphan: uint256 randomhash = GetRandHash(); - map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + map::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); @@ -238,55 +352,62 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) ////////////////////////////////////////////////////////////////////////////// // -// CTransaction and CTxIndex +// CTransaction / CTxOut // -bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet) +bool CTxOut::IsDust() const { - SetNull(); - if (!txdb.ReadTxIndex(prevout.hash, txindexRet)) - return false; - if (!ReadFromDisk(txindexRet.pos)) - return false; - if (prevout.n >= vout.size()) - { - SetNull(); + // CasinoCoin: IsDust() detection disabled, allows any valid dust to be relayed. + // The fees imposed on each dust txo is considered sufficient spam deterrant. + return false; +} + +bool CTransaction::IsStandard(string& strReason) const +{ + if (nVersion > CTransaction::CURRENT_VERSION || nVersion < 1) { + strReason = "version"; return false; } - return true; -} -bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout) -{ - CTxIndex txindex; - return ReadFromDisk(txdb, prevout, txindex); -} - -bool CTransaction::ReadFromDisk(COutPoint prevout) -{ - CTxDB txdb("r"); - CTxIndex txindex; - return ReadFromDisk(txdb, prevout, txindex); -} - -bool CTransaction::IsStandard() const -{ - if (nVersion > CTransaction::CURRENT_VERSION) + if (!IsFinal()) { + strReason = "not-final"; return false; + } + + // Extremely large transactions with lots of inputs can cost the network + // almost as much to process as they cost the sender in fees, because + // computing signature hashes is O(ninputs*txsize). Limiting transactions + // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. + unsigned int sz = this->GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + if (sz >= MAX_STANDARD_TX_SIZE) { + strReason = "tx-size"; + return false; + } BOOST_FOREACH(const CTxIn& txin, vin) { // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG // pay-to-script-hash, which is 3 ~80-byte signatures, 3 // ~65-byte public keys, plus a few script ops. - if (txin.scriptSig.size() > 500) + if (txin.scriptSig.size() > 500) { + strReason = "scriptsig-size"; return false; - if (!txin.scriptSig.IsPushOnly()) + } + if (!txin.scriptSig.IsPushOnly()) { + strReason = "scriptsig-not-pushonly"; return false; + } } - BOOST_FOREACH(const CTxOut& txout, vout) - if (!::IsStandard(txout.scriptPubKey)) + BOOST_FOREACH(const CTxOut& txout, vout) { + if (!::IsStandard(txout.scriptPubKey)) { + strReason = "scriptpubkey"; return false; + } + if (txout.IsDust()) { + strReason = "dust"; + return false; + } + } return true; } @@ -301,7 +422,7 @@ bool CTransaction::IsStandard() const // expensive-to-check-upon-redemption script like: // DUP CHECKSIG DROP ... repeated 100 times... OP_1 // -bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const +bool CTransaction::AreInputsStandard(CCoinsViewCache& mapInputs) const { if (IsCoinBase()) return true; // Coinbases don't use vin normally @@ -326,7 +447,7 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const // beside "push data" in the scriptSig the // IsStandard() call returns false vector > stack; - if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0)) + if (!EvalScript(stack, vin[i].scriptSig, *this, i, false, 0)) return false; if (whichType == TX_SCRIPTHASH) @@ -355,8 +476,7 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const return true; } -unsigned int -CTransaction::GetLegacySigOpCount() const +unsigned int CTransaction::GetLegacySigOpCount() const { unsigned int nSigOps = 0; BOOST_FOREACH(const CTxIn& txin, vin) @@ -373,25 +493,21 @@ CTransaction::GetLegacySigOpCount() const int CMerkleTx::SetMerkleBranch(const CBlock* pblock) { - if (fClient) - { - if (hashBlock == 0) - return 0; - } - else - { - CBlock blockTmp; - if (pblock == NULL) - { - // Load the block this tx is in - CTxIndex txindex; - if (!CTxDB("r").ReadTxIndex(GetHash(), txindex)) - return 0; - if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos)) - return 0; - pblock = &blockTmp; - } + CBlock blockTmp; + if (pblock == NULL) { + CCoins coins; + if (pcoinsTip->GetCoins(GetHash(), coins)) { + CBlockIndex *pindex = FindBlockByHeight(coins.nHeight); + if (pindex) { + if (!blockTmp.ReadFromDisk(pindex)) + return 0; + pblock = &blockTmp; + } + } + } + + if (pblock) { // Update the tx's hashBlock hashBlock = pblock->GetHash(); @@ -428,28 +544,28 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) -bool CTransaction::CheckTransaction() const +bool CTransaction::CheckTransaction(CValidationState &state) const { // Basic checks that don't depend on any context if (vin.empty()) - return DoS(10, error("CTransaction::CheckTransaction() : vin empty")); + return state.DoS(10, error("CTransaction::CheckTransaction() : vin empty")); if (vout.empty()) - return DoS(10, error("CTransaction::CheckTransaction() : vout empty")); + return state.DoS(10, error("CTransaction::CheckTransaction() : vout empty")); // Size limits if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return DoS(100, error("CTransaction::CheckTransaction() : size limits failed")); + return state.DoS(100, error("CTransaction::CheckTransaction() : size limits failed")); // Check for negative or overflow output values int64 nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, vout) { if (txout.nValue < 0) - return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative")); + return state.DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative")); if (txout.nValue > MAX_MONEY) - return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high")); + return state.DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high")); nValueOut += txout.nValue; if (!MoneyRange(nValueOut)) - return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range")); + return state.DoS(100, error("CTransaction::CheckTransaction() : txout total out of range")); } // Check for duplicate inputs @@ -457,56 +573,109 @@ bool CTransaction::CheckTransaction() const BOOST_FOREACH(const CTxIn& txin, vin) { if (vInOutPoints.count(txin.prevout)) - return false; + return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs")); vInOutPoints.insert(txin.prevout); } if (IsCoinBase()) { if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100) - return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size")); + return state.DoS(100, error("CTransaction::CheckTransaction() : coinbase script size")); } else { BOOST_FOREACH(const CTxIn& txin, vin) if (txin.prevout.IsNull()) - return DoS(10, error("CTransaction::CheckTransaction() : prevout is null")); + return state.DoS(10, error("CTransaction::CheckTransaction() : prevout is null")); } return true; } -bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, +int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, + enum GetMinFee_mode mode) const +{ + // Base fee is either nMinTxFee or nMinRelayTxFee + int64 nBaseFee = (mode == GMF_RELAY) ? nMinRelayTxFee : nMinTxFee; + + unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); + unsigned int nNewBlockSize = nBlockSize + nBytes; + int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; + + if (fAllowFree) + { + // There is a free transaction area in blocks created by most miners, + // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 + // to be considered to fall into this category. We don't want to encourage sending + // multiple transactions instead of one big transaction to avoid fees. + // * If we are creating a transaction we allow transactions up to 5,000 bytes + // to be considered safe and assume they can likely make it into this section. + if (nBytes < (mode == GMF_SEND ? 5000 : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))) + nMinFee = 0; + } + + // CasinoCoin + // To limit dust spam, add nBaseFee for each output less than DUST_SOFT_LIMIT + BOOST_FOREACH(const CTxOut& txout, vout) + if (txout.nValue < DUST_SOFT_LIMIT) + nMinFee += nBaseFee; + + // Raise the price as the block approaches full + if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) + { + if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN) + return MAX_MONEY; + nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize); + } + + if (!MoneyRange(nMinFee)) + nMinFee = MAX_MONEY; + return nMinFee; +} + +void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) +{ + LOCK(cs); + + std::map::iterator it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); + + // iterate over all COutPoints in mapNextTx whose hash equals the provided hashTx + while (it != mapNextTx.end() && it->first.hash == hashTx) { + coins.Spend(it->first.n); // and remove those outputs from coins + it++; + } +} + +bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs) { if (pfMissingInputs) *pfMissingInputs = false; - if (!tx.CheckTransaction()) + if (!tx.CheckTransaction(state)) return error("CTxMemPool::accept() : CheckTransaction failed"); // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx")); + return state.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx")); // To help v0.1.5 clients who would see it as a negative number if ((int64)tx.nLockTime > std::numeric_limits::max()) return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); // Rather not work on nonstandard transactions (unless -testnet) - if (!fTestNet && !tx.IsStandard()) - return error("CTxMemPool::accept() : nonstandard transaction type"); + string strNonStd; + if (!fTestNet && !tx.IsStandard(strNonStd)) + return error("CTxMemPool::accept() : nonstandard transaction (%s)", + strNonStd.c_str()); - // Do we already have it? + // is it already in the memory pool? uint256 hash = tx.GetHash(); { LOCK(cs); if (mapTx.count(hash)) return false; } - if (fCheckInputs) - if (txdb.ContainsTx(hash)) - return false; // Check for conflicts with in-memory transactions CTransaction* ptxOld = NULL; @@ -538,66 +707,86 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, if (fCheckInputs) { - MapPrevTx mapInputs; - map mapUnused; - bool fInvalid = false; - if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) + CCoinsView dummy; + CCoinsViewCache view(dummy); + { - if (fInvalid) - return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str()); - if (pfMissingInputs) - *pfMissingInputs = true; + LOCK(cs); + CCoinsViewMemPool viewMemPool(*pcoinsTip, *this); + view.SetBackend(viewMemPool); + + // do we already have it? + if (view.HaveCoins(hash)) return false; + + // do all inputs exist? + // Note that this does not check for the presence of actual outputs (see the next check for that), + // only helps filling in pfMissingInputs (to determine missing vs spent). + BOOST_FOREACH(const CTxIn txin, tx.vin) { + if (!view.HaveCoins(txin.prevout.hash)) { + if (pfMissingInputs) + *pfMissingInputs = true; + return false; + } + } + + // are the actual inputs available? + if (!tx.HaveInputs(view)) + return state.Invalid(error("CTxMemPool::accept() : inputs already spent")); + + // Bring the best block into scope + view.GetBestBlock(); + + // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool + view.SetBackend(dummy); } // Check for non-standard pay-to-script-hash in inputs - if (!tx.AreInputsStandard(mapInputs) && !fTestNet) + if (!tx.AreInputsStandard(view) && !fTestNet) return error("CTxMemPool::accept() : nonstandard transaction input"); // Note: if you modify this code to accept non-standard transactions, then // you should add code here to check that the transaction does a // reasonable number of ECDSA signature verifications. - int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); + int64 nFees = tx.GetValueIn(view)-tx.GetValueOut(); unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Don't accept it if it can't get into a block int64 txMinFee = tx.GetMinFee(1000, true, GMF_RELAY); - if (nFees < txMinFee) + if (fLimitFree && nFees < txMinFee) return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d, hash.ToString().c_str(), nFees, txMinFee); // Continuously rate-limit free transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to - // be annoying or make other's transactions take longer to confirm. - if (nFees < MIN_RELAY_TX_FEE) + // be annoying or make others' transactions take longer to confirm. + if (fLimitFree && nFees < CTransaction::nMinRelayTxFee) { - static CCriticalSection cs; static double dFreeCount; static int64 nLastTime; int64 nNow = GetTime(); - { - LOCK(cs); - // 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 > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx)) - return error("CTxMemPool::accept() : free transaction rejected by rate limiter"); - if (fDebug) - printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); - dFreeCount += nSize; - } + LOCK(cs); + + // 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 >= GetArg("-limitfreerelay", 15)*10*1000) + return error("CTxMemPool::accept() : free transaction rejected by rate limiter"); + if (fDebug) + printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); + dFreeCount += nSize; } // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) + if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC)) { - return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); + return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().c_str()); } } @@ -616,19 +805,21 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, // If updated, erase old tx from wallet if (ptxOld) EraseFromWallets(ptxOld->GetHash()); + SyncWithWallets(hash, tx, NULL, true); - printf("CTxMemPool::accept() : accepted %s (poolsz %u)\n", - hash.ToString().c_str(), - mapTx.size()); return true; } -bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs) +bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs) { - return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs); + try { + return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs); + } catch(std::runtime_error &e) { + return state.Abort(_("System error: ") + e.what()); + } } -bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx) +bool CTxMemPool::addUnchecked(const uint256& hash, const CTransaction &tx) { // Add to memory pool without checking anything. Don't call this directly, // call CTxMemPool::accept to properly check the transaction first. @@ -642,12 +833,19 @@ bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx) } -bool CTxMemPool::remove(CTransaction &tx) +bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive) { // Remove transaction from memory pool { LOCK(cs); uint256 hash = tx.GetHash(); + if (fRecursive) { + for (unsigned int i = 0; i < tx.vout.size(); i++) { + std::map::iterator it = mapNextTx.find(COutPoint(hash, i)); + if (it != mapNextTx.end()) + remove(*it->second.ptx, true); + } + } if (mapTx.count(hash)) { BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -659,6 +857,29 @@ bool CTxMemPool::remove(CTransaction &tx) return true; } +bool CTxMemPool::removeConflicts(const CTransaction &tx) +{ + // Remove transactions which depend on inputs of tx, recursively + LOCK(cs); + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + std::map::iterator it = mapNextTx.find(txin.prevout); + if (it != mapNextTx.end()) { + const CTransaction &txConflict = *it->second.ptx; + if (txConflict != tx) + remove(txConflict, true); + } + } + return true; +} + +void CTxMemPool::clear() +{ + LOCK(cs); + mapTx.clear(); + mapNextTx.clear(); + ++nTransactionsUpdated; +} + void CTxMemPool::queryHashes(std::vector& vtxid) { vtxid.clear(); @@ -706,31 +927,16 @@ int CMerkleTx::GetBlocksToMaturity() const } -bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs) +bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree) { - if (fClient) - { - if (!IsInMainChain() && !ClientConnectInputs()) - return false; - return CTransaction::AcceptToMemoryPool(txdb, false); - } - else - { - return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs); - } -} - -bool CMerkleTx::AcceptToMemoryPool() -{ - CTxDB txdb("r"); - return AcceptToMemoryPool(txdb); + CValidationState state; + return CTransaction::AcceptToMemoryPool(state, fCheckInputs, fLimitFree); } -bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) +bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs) { - { LOCK(mempool.cs); // Add previous supporting transactions first @@ -739,60 +945,76 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) if (!tx.IsCoinBase()) { uint256 hash = tx.GetHash(); - if (!mempool.exists(hash) && !txdb.ContainsTx(hash)) - tx.AcceptToMemoryPool(txdb, fCheckInputs); + if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash)) + tx.AcceptToMemoryPool(fCheckInputs, false); } } - return AcceptToMemoryPool(txdb, fCheckInputs); + return AcceptToMemoryPool(fCheckInputs, false); } return false; } -bool CWalletTx::AcceptWalletTransaction() -{ - CTxDB txdb("r"); - return AcceptWalletTransaction(txdb); -} - -int CTxIndex::GetDepthInMainChain() const -{ - // Read block header - CBlock block; - if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false)) - return 0; - // Find the block in the index - map::iterator mi = mapBlockIndex.find(block.GetHash()); - if (mi == mapBlockIndex.end()) - return 0; - CBlockIndex* pindex = (*mi).second; - if (!pindex || !pindex->IsInMainChain()) - return 0; - return 1 + nBestHeight - pindex->nHeight; -} // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock -bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) +bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { + CBlockIndex *pindexSlow = NULL; { LOCK(cs_main); { LOCK(mempool.cs); if (mempool.exists(hash)) { - tx = mempool.lookup(hash); + txOut = mempool.lookup(hash); return true; } } - CTxDB txdb("r"); - CTxIndex txindex; - if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) - { - CBlock block; - if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) - hashBlock = block.GetHash(); - return true; + + if (fTxIndex) { + CDiskTxPos postx; + if (pblocktree->ReadTxIndex(hash, postx)) { + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + CBlockHeader header; + try { + file >> header; + fseek(file, postx.nTxOffset, SEEK_CUR); + file >> txOut; + } catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + hashBlock = header.GetHash(); + if (txOut.GetHash() != hash) + return error("%s() : txid mismatch", __PRETTY_FUNCTION__); + return true; + } + } + + if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it + int nHeight = -1; + { + CCoinsViewCache &view = *pcoinsTip; + CCoins coins; + if (view.GetCoins(hash, coins)) + nHeight = coins.nHeight; + } + if (nHeight > 0) + pindexSlow = FindBlockByHeight(nHeight); } } + + if (pindexSlow) { + CBlock block; + if (block.ReadFromDisk(pindexSlow)) { + BOOST_FOREACH(const CTransaction &tx, block.vtx) { + if (tx.GetHash() == hash) { + txOut = tx; + hashBlock = pindexSlow->GetBlockHash(); + return true; + } + } + } + } + return false; } @@ -801,28 +1023,39 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) - - ////////////////////////////////////////////////////////////////////////////// // // CBlock and CBlockIndex // -bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions) +static CBlockIndex* pblockindexFBBHLast; +CBlockIndex* FindBlockByHeight(int nHeight) { - if (!fReadTransactions) - { - *this = pindex->GetBlockHeader(); - return true; - } - if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions)) + CBlockIndex *pblockindex; + if (nHeight < nBestHeight / 2) + pblockindex = pindexGenesisBlock; + else + pblockindex = pindexBest; + if (pblockindexFBBHLast && abs(nHeight - pblockindex->nHeight) > abs(nHeight - pblockindexFBBHLast->nHeight)) + pblockindex = pblockindexFBBHLast; + while (pblockindex->nHeight > nHeight) + pblockindex = pblockindex->pprev; + while (pblockindex->nHeight < nHeight) + pblockindex = pblockindex->pnext; + pblockindexFBBHLast = pblockindex; + return pblockindex; +} + +bool CBlock::ReadFromDisk(const CBlockIndex* pindex) +{ + if (!ReadFromDisk(pindex->GetBlockPos())) return false; if (GetHash() != pindex->GetBlockHash()) return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); return true; } -uint256 static GetOrphanRoot(const CBlock* pblock) +uint256 static GetOrphanRoot(const CBlockHeader* pblock) { // Work back to the first block in the orphan chain while (mapOrphanBlocks.count(pblock->hashPrevBlock)) @@ -881,8 +1114,8 @@ int64 static GetBlockValue(int nHeight, int64 nFees) return nSubsidy + nFees; } -static const int64 nTargetTimespan = 0.25 * 24 * 60 * 60; // 0.25 day / 6 hours -static const int64 nTargetSpacing = 1 * 30; // 30 seconds +static const int64 nTargetTimespan = 0.25 * 24 * 60 * 60; // CasinoCoin: 0.25 day / 6 hours +static const int64 nTargetSpacing = 1 * 30; // CasinoCoin: 30 seconds static const int64 nInterval = nTargetTimespan / nTargetSpacing; // @@ -910,7 +1143,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) return bnResult.GetCompact(); } -unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock) +unsigned int static GetNextWorkRequired_V1(const CBlockIndex* pindexLast, const CBlockHeader *pblock) { unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact(); @@ -971,7 +1204,7 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl bnNew = bnProofOfWorkLimit; /// debug print - printf("GetNextWorkRequired RETARGET\n"); + printf("Difficulty Retarget - GetNextWorkRequired_V1 RETARGET\n"); printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan); printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str()); printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str()); @@ -979,6 +1212,100 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl return bnNew.GetCompact(); } +unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const CBlockHeader *pblock, uint64 TargetBlocksSpacingSeconds, uint64 PastBlocksMin, uint64 PastBlocksMax) +{ + /* Kimoto Gravity Well implementation - credit to Dr Kimoto Chan of Megacoin */ + const CBlockIndex *BlockLastSolved = pindexLast; + const CBlockIndex *BlockReading = pindexLast; + const CBlockHeader *BlockCreating = pblock; + BlockCreating = BlockCreating; + uint64 PastBlocksMass = 0; + int64 PastRateActualSeconds = 0; + int64 PastRateTargetSeconds = 0; + double PastRateAdjustmentRatio = double(1); + CBigNum PastDifficultyAverage; + CBigNum PastDifficultyAveragePrev; + double EventHorizonDeviation; + double EventHorizonDeviationFast; + double EventHorizonDeviationSlow; + + if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || (uint64)BlockLastSolved->nHeight < PastBlocksMin) { return bnProofOfWorkLimit.GetCompact(); } + + for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) + { + if (PastBlocksMax > 0 && i > PastBlocksMax) { break; } + PastBlocksMass++; + + if (i == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); } + else { PastDifficultyAverage = ((CBigNum().SetCompact(BlockReading->nBits) - PastDifficultyAveragePrev) / i) + PastDifficultyAveragePrev; } + PastDifficultyAveragePrev = PastDifficultyAverage; + + PastRateActualSeconds = BlockLastSolved->GetBlockTime() - BlockReading->GetBlockTime(); + PastRateTargetSeconds = TargetBlocksSpacingSeconds * PastBlocksMass; + PastRateAdjustmentRatio = double(1); + if (PastRateActualSeconds < 0) { PastRateActualSeconds = 0; } + if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) + { + PastRateAdjustmentRatio = double(PastRateTargetSeconds) / double(PastRateActualSeconds); + } + EventHorizonDeviation = 1 + (0.7084 * pow((double(PastBlocksMass)/double(28.2)), -1.228)); + EventHorizonDeviationFast = EventHorizonDeviation; + EventHorizonDeviationSlow = 1 / EventHorizonDeviation; + + if (PastBlocksMass >= PastBlocksMin) + { + if ((PastRateAdjustmentRatio <= EventHorizonDeviationSlow) || (PastRateAdjustmentRatio >= EventHorizonDeviationFast)) { assert(BlockReading); break; } + } + if (BlockReading->pprev == NULL) { assert(BlockReading); break; } + BlockReading = BlockReading->pprev; + } + + CBigNum bnNew(PastDifficultyAverage); + if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) + { + bnNew *= PastRateActualSeconds; + bnNew /= PastRateTargetSeconds; + } + if (bnNew > bnProofOfWorkLimit) { bnNew = bnProofOfWorkLimit; } + + /// debug print + printf("Difficulty Retarget - Kimoto Gravity Well RETARGET\n"); + printf("PastRateAdjustmentRatio = %g\n", PastRateAdjustmentRatio); + printf("Before: %08x %s\n", BlockLastSolved->nBits, CBigNum().SetCompact(BlockLastSolved->nBits).getuint256().ToString().c_str()); + printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str()); + + return bnNew.GetCompact(); +} + +unsigned int static GetNextWorkRequired_V2(const CBlockIndex* pindexLast, const CBlockHeader *pblock) +{ + static const int64 BlocksTargetSpacing = 1 * 30; // CasinoCoin: 30 seconds + unsigned int TimeDaySeconds = 60 * 60 * 24; + int64 PastSecondsMin = TimeDaySeconds * 0.01; + int64 PastSecondsMax = TimeDaySeconds * 0.14; + uint64 PastBlocksMin = PastSecondsMin / BlocksTargetSpacing; + uint64 PastBlocksMax = PastSecondsMax / BlocksTargetSpacing; + + return KimotoGravityWell(pindexLast, pblock, BlocksTargetSpacing, PastBlocksMin, PastBlocksMax); +} + +unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) +{ + int DiffMode = 1; + if (fTestNet) + { + if (pindexLast->nHeight+1 >= 100) { DiffMode = 2; } + } + else + { + if (pindexLast->nHeight+1 >= 227000) { DiffMode = 2; } + } + + if (DiffMode == 1) { return GetNextWorkRequired_V1(pindexLast, pblock); } + else if (DiffMode == 2) { return GetNextWorkRequired_V2(pindexLast, pblock); } + return GetNextWorkRequired_V2(pindexLast, pblock); +} + bool CheckProofOfWork(uint256 hash, unsigned int nBits) { CBigNum bnTarget; @@ -1003,7 +1330,7 @@ int GetNumBlocksOfPeers() bool IsInitialBlockDownload() { - if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate()) + if (pindexBest == NULL || fImporting || fReindex || nBestHeight < Checkpoints::GetTotalBlocksEstimate()) return true; static int64 nLastUpdate; static CBlockIndex* pindexLastBest; @@ -1018,24 +1345,87 @@ bool IsInitialBlockDownload() void static InvalidChainFound(CBlockIndex* pindexNew) { - if (pindexNew->bnChainWork > bnBestInvalidWork) + if (pindexNew->nChainWork > nBestInvalidWork) { - bnBestInvalidWork = pindexNew->bnChainWork; - CTxDB().WriteBestInvalidWork(bnBestInvalidWork); + nBestInvalidWork = pindexNew->nChainWork; + pblocktree->WriteBestInvalidWork(CBigNum(nBestInvalidWork)); uiInterface.NotifyBlocksChanged(); } - printf("InvalidChainFound: invalid block=%s height=%d work=%s date=%s\n", - pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, - pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", + printf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n", + pindexNew->GetBlockHash().ToString().c_str(), pindexNew->nHeight, + log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()).c_str()); - printf("InvalidChainFound: current best=%s height=%d work=%s date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), - DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6) - printf("InvalidChainFound: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); + printf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n", + hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + if (pindexBest && nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256()) + printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); } -void CBlock::UpdateTime(const CBlockIndex* pindexPrev) +void static InvalidBlockFound(CBlockIndex *pindex) { + pindex->nStatus |= BLOCK_FAILED_VALID; + pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex)); + setBlockIndexValid.erase(pindex); + InvalidChainFound(pindex); + if (pindex->pnext) { + CValidationState stateDummy; + ConnectBestBlock(stateDummy); // reorganise away from the failed block + } +} + +bool ConnectBestBlock(CValidationState &state) { + do { + CBlockIndex *pindexNewBest; + + { + std::set::reverse_iterator it = setBlockIndexValid.rbegin(); + if (it == setBlockIndexValid.rend()) + return true; + pindexNewBest = *it; + } + + if (pindexNewBest == pindexBest || (pindexBest && pindexNewBest->nChainWork == pindexBest->nChainWork)) + return true; // nothing to do + + // check ancestry + CBlockIndex *pindexTest = pindexNewBest; + std::vector vAttach; + do { + if (pindexTest->nStatus & BLOCK_FAILED_MASK) { + // mark descendants failed + CBlockIndex *pindexFailed = pindexNewBest; + while (pindexTest != pindexFailed) { + pindexFailed->nStatus |= BLOCK_FAILED_CHILD; + setBlockIndexValid.erase(pindexFailed); + pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexFailed)); + pindexFailed = pindexFailed->pprev; + } + InvalidChainFound(pindexNewBest); + break; + } + + if (pindexBest == NULL || pindexTest->nChainWork > pindexBest->nChainWork) + vAttach.push_back(pindexTest); + + if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) { + reverse(vAttach.begin(), vAttach.end()); + BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) { + boost::this_thread::interruption_point(); + try { + if (!SetBestChain(state, pindexSwitch)) + return false; + } catch(std::runtime_error &e) { + return state.Abort(_("System error: ") + e.what()); + } + } + return true; + } + pindexTest = pindexTest->pprev; + } while(true); + } while(true); +} + +void CBlockHeader::UpdateTime(const CBlockIndex* pindexPrev) { nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); @@ -1054,145 +1444,26 @@ void CBlock::UpdateTime(const CBlockIndex* pindexPrev) -bool CTransaction::DisconnectInputs(CTxDB& txdb) +const CTxOut &CTransaction::GetOutputFor(const CTxIn& input, CCoinsViewCache& view) { - // Relinquish previous transactions' spent pointers - if (!IsCoinBase()) - { - BOOST_FOREACH(const CTxIn& txin, vin) - { - COutPoint prevout = txin.prevout; - - // Get prev txindex from disk - CTxIndex txindex; - if (!txdb.ReadTxIndex(prevout.hash, txindex)) - return error("DisconnectInputs() : ReadTxIndex failed"); - - if (prevout.n >= txindex.vSpent.size()) - return error("DisconnectInputs() : prevout.n out of range"); - - // Mark outpoint as not spent - txindex.vSpent[prevout.n].SetNull(); - - // Write back - if (!txdb.UpdateTxIndex(prevout.hash, txindex)) - return error("DisconnectInputs() : UpdateTxIndex failed"); - } - } - - // Remove transaction from index - // This can fail if a duplicate of this transaction was in a chain that got - // reorganized away. This is only possible if this transaction was completely - // spent, so erasing it would be a no-op anway. - txdb.EraseTxIndex(*this); - - return true; + const CCoins &coins = view.GetCoins(input.prevout.hash); + assert(coins.IsAvailable(input.prevout.n)); + return coins.vout[input.prevout.n]; } - -bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTestPool, - bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid) -{ - // FetchInputs can return false either because we just haven't seen some inputs - // (in which case the transaction should be stored as an orphan) - // or because the transaction is malformed (in which case the transaction should - // be dropped). If tx is definitely invalid, fInvalid will be set to true. - fInvalid = false; - - if (IsCoinBase()) - return true; // Coinbase transactions have no inputs to fetch. - - for (unsigned int i = 0; i < vin.size(); i++) - { - COutPoint prevout = vin[i].prevout; - if (inputsRet.count(prevout.hash)) - continue; // Got it already - - // Read txindex - CTxIndex& txindex = inputsRet[prevout.hash].first; - bool fFound = true; - if ((fBlock || fMiner) && mapTestPool.count(prevout.hash)) - { - // Get txindex from current proposed changes - txindex = mapTestPool.find(prevout.hash)->second; - } - else - { - // Read txindex from txdb - fFound = txdb.ReadTxIndex(prevout.hash, txindex); - } - if (!fFound && (fBlock || fMiner)) - return fMiner ? false : error("FetchInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); - - // Read txPrev - CTransaction& txPrev = inputsRet[prevout.hash].second; - if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) - { - // Get prev tx from single transactions in memory - { - LOCK(mempool.cs); - if (!mempool.exists(prevout.hash)) - return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); - txPrev = mempool.lookup(prevout.hash); - } - if (!fFound) - txindex.vSpent.resize(txPrev.vout.size()); - } - else - { - // Get prev tx from disk - if (!txPrev.ReadFromDisk(txindex.pos)) - return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); - } - } - - // Make sure all prevout.n's are valid: - for (unsigned int i = 0; i < vin.size(); i++) - { - const COutPoint prevout = vin[i].prevout; - assert(inputsRet.count(prevout.hash) != 0); - const CTxIndex& txindex = inputsRet[prevout.hash].first; - const CTransaction& txPrev = inputsRet[prevout.hash].second; - if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) - { - // Revisit this if/when transaction replacement is implemented and allows - // adding inputs: - fInvalid = true; - return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); - } - } - - return true; -} - -const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const -{ - MapPrevTx::const_iterator mi = inputs.find(input.prevout.hash); - if (mi == inputs.end()) - throw std::runtime_error("CTransaction::GetOutputFor() : prevout.hash not found"); - - const CTransaction& txPrev = (mi->second).second; - if (input.prevout.n >= txPrev.vout.size()) - throw std::runtime_error("CTransaction::GetOutputFor() : prevout.n out of range"); - - return txPrev.vout[input.prevout.n]; -} - -int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const +int64 CTransaction::GetValueIn(CCoinsViewCache& inputs) const { if (IsCoinBase()) return 0; int64 nResult = 0; for (unsigned int i = 0; i < vin.size(); i++) - { nResult += GetOutputFor(vin[i], inputs).nValue; - } - return nResult; + return nResult; } -unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const +unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const { if (IsCoinBase()) return 0; @@ -1200,147 +1471,137 @@ unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const unsigned int nSigOps = 0; for (unsigned int i = 0; i < vin.size(); i++) { - const CTxOut& prevout = GetOutputFor(vin[i], inputs); + const CTxOut &prevout = GetOutputFor(vin[i], inputs); if (prevout.scriptPubKey.IsPayToScriptHash()) nSigOps += prevout.scriptPubKey.GetSigOpCount(vin[i].scriptSig); } return nSigOps; } -bool CTransaction::ConnectInputs(MapPrevTx inputs, - map& mapTestPool, const CDiskTxPos& posThisTx, - const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash) +void CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const +{ + // mark inputs spent + if (!IsCoinBase()) { + BOOST_FOREACH(const CTxIn &txin, vin) { + CCoins &coins = inputs.GetCoins(txin.prevout.hash); + CTxInUndo undo; + assert(coins.Spend(txin.prevout, undo)); + txundo.vprevout.push_back(undo); + } + } + + // add outputs + assert(inputs.SetCoins(txhash, CCoins(*this, nHeight))); +} + +bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const +{ + if (!IsCoinBase()) { + // first check whether information about the prevout hash is available + for (unsigned int i = 0; i < vin.size(); i++) { + const COutPoint &prevout = vin[i].prevout; + if (!inputs.HaveCoins(prevout.hash)) + return false; + } + + // then check whether the actual outputs are available + for (unsigned int i = 0; i < vin.size(); i++) { + const COutPoint &prevout = vin[i].prevout; + const CCoins &coins = inputs.GetCoins(prevout.hash); + if (!coins.IsAvailable(prevout.n)) + return false; + } + } + return true; +} + +bool CScriptCheck::operator()() const { + const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; + if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags, nHashType)) + return error("CScriptCheck() : %s VerifySignature failed", ptxTo->GetHash().ToString().c_str()); + return true; +} + +bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) +{ + return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)(); +} + +bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector *pvChecks) const { - // Take over previous transactions' spent pointers - // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain - // fMiner is true when called from the internal casinocoin miner - // ... both are false when called from CTransaction::AcceptToMemoryPool if (!IsCoinBase()) { + if (pvChecks) + pvChecks->reserve(vin.size()); + + // This doesn't trigger the DoS code on purpose; if it did, it would make it easier + // for an attacker to attempt to split the network. + if (!HaveInputs(inputs)) + return state.Invalid(error("CheckInputs() : %s inputs unavailable", GetHash().ToString().c_str())); + + // While checking, GetBestBlock() refers to the parent block. + // This is also true for mempool checks. + int nSpendHeight = inputs.GetBestBlock()->nHeight + 1; int64 nValueIn = 0; int64 nFees = 0; for (unsigned int i = 0; i < vin.size(); i++) { - COutPoint prevout = vin[i].prevout; - assert(inputs.count(prevout.hash) > 0); - CTxIndex& txindex = inputs[prevout.hash].first; - CTransaction& txPrev = inputs[prevout.hash].second; - - if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) - return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + const COutPoint &prevout = vin[i].prevout; + const CCoins &coins = inputs.GetCoins(prevout.hash); // If prev is coinbase, check that it's matured - if (txPrev.IsCoinBase()) - for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev) - if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) - return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight); + if (coins.IsCoinBase()) { + if (nSpendHeight - coins.nHeight < COINBASE_MATURITY) + return state.Invalid(error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight)); + } // Check for negative or overflow input values - nValueIn += txPrev.vout[prevout.n].nValue; - if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return DoS(100, error("ConnectInputs() : txin values out of range")); + nValueIn += coins.vout[prevout.n].nValue; + if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) + return state.DoS(100, error("CheckInputs() : txin values out of range")); } - // The first loop above does all the inexpensive checks. - // Only if ALL inputs pass do we perform expensive ECDSA signature checks. - // Helps prevent CPU exhaustion attacks. - for (unsigned int i = 0; i < vin.size(); i++) - { - COutPoint prevout = vin[i].prevout; - assert(inputs.count(prevout.hash) > 0); - CTxIndex& txindex = inputs[prevout.hash].first; - CTransaction& txPrev = inputs[prevout.hash].second; - - // Check for conflicts (double-spend) - // This doesn't trigger the DoS code on purpose; if it did, it would make it easier - // for an attacker to attempt to split the network. - if (!txindex.vSpent[prevout.n].IsNull()) - return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str()); - - // Skip ECDSA signature verification when connecting blocks (fBlock=true) - // before the last blockchain checkpoint. This is safe because block merkle hashes are - // still computed and checked, and any change will be caught at the next checkpoint. - if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate()))) - { - // Verify signature - if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0)) - { - // only during transition phase for P2SH: do not invoke anti-DoS code for - // potentially old clients relaying bad P2SH transactions - if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0)) - return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str()); - - return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str())); - } - } - - // Mark outpoints as spent - txindex.vSpent[prevout.n] = posThisTx; - - // Write back - if (fBlock || fMiner) - { - mapTestPool[prevout.hash] = txindex; - } - } if (nValueIn < GetValueOut()) - return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str())); + return state.DoS(100, error("CheckInputs() : %s value in < value out", GetHash().ToString().c_str())); // Tally transaction fees int64 nTxFee = nValueIn - GetValueOut(); if (nTxFee < 0) - return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str())); + return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", GetHash().ToString().c_str())); nFees += nTxFee; if (!MoneyRange(nFees)) - return DoS(100, error("ConnectInputs() : nFees out of range")); - } + return state.DoS(100, error("CheckInputs() : nFees out of range")); - return true; -} + // The first loop above does all the inexpensive checks. + // 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. This is safe because block merkle hashes are + // still computed and checked, and any change will be caught at the next checkpoint. + if (fScriptChecks) { + for (unsigned int i = 0; i < vin.size(); i++) { + const COutPoint &prevout = vin[i].prevout; + const CCoins &coins = inputs.GetCoins(prevout.hash); -bool CTransaction::ClientConnectInputs() -{ - if (IsCoinBase()) - return false; - - // Take over previous transactions' spent pointers - { - LOCK(mempool.cs); - int64 nValueIn = 0; - for (unsigned int i = 0; i < vin.size(); i++) - { - // Get prev tx from single transactions in memory - COutPoint prevout = vin[i].prevout; - if (!mempool.exists(prevout.hash)) - return false; - CTransaction& txPrev = mempool.lookup(prevout.hash); - - if (prevout.n >= txPrev.vout.size()) - return false; - - // Verify signature - if (!VerifySignature(txPrev, *this, i, true, 0)) - return error("ConnectInputs() : VerifySignature failed"); - - ///// this is redundant with the mempool.mapNextTx stuff, - ///// not sure which I want to get rid of - ///// this has to go away now that posNext is gone - // // Check for conflicts - // if (!txPrev.vout[prevout.n].posNext.IsNull()) - // return error("ConnectInputs() : prev tx already used"); - // - // // Flag outpoints as used - // txPrev.vout[prevout.n].posNext = posThisTx; - - nValueIn += txPrev.vout[prevout.n].nValue; - - if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return error("ClientConnectInputs() : txin values out of range"); + // Verify signature + CScriptCheck check(coins, *this, i, flags, 0); + if (pvChecks) { + pvChecks->push_back(CScriptCheck()); + check.swap(pvChecks->back()); + } else if (!check()) { + if (flags & SCRIPT_VERIFY_STRICTENC) { + // For now, check whether the failure was caused by non-canonical + // encodings or not; if so, don't trigger DoS protection. + CScriptCheck check(coins, *this, i, flags & (~SCRIPT_VERIFY_STRICTENC), 0); + if (check()) + return state.Invalid(); + } + return state.DoS(100,false); + } + } } - if (GetValueOut() > nValueIn) - return false; } return true; @@ -1349,32 +1610,144 @@ bool CTransaction::ClientConnectInputs() -bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) +bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean) { - // Disconnect in reverse order - for (int i = vtx.size()-1; i >= 0; i--) - if (!vtx[i].DisconnectInputs(txdb)) - return false; + assert(pindex == view.GetBestBlock()); - // Update block index on disk without changing it in memory. - // The memory index structure will be changed after the db commits. - if (pindex->pprev) - { - CDiskBlockIndex blockindexPrev(pindex->pprev); - blockindexPrev.hashNext = 0; - if (!txdb.WriteBlockIndex(blockindexPrev)) - return error("DisconnectBlock() : WriteBlockIndex failed"); + if (pfClean) + *pfClean = false; + + bool fClean = true; + + CBlockUndo blockUndo; + CDiskBlockPos pos = pindex->GetUndoPos(); + if (pos.IsNull()) + return error("DisconnectBlock() : no undo data available"); + if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) + return error("DisconnectBlock() : failure reading undo data"); + + if (blockUndo.vtxundo.size() + 1 != vtx.size()) + return error("DisconnectBlock() : block and undo data inconsistent"); + + // undo transactions in reverse order + for (int i = vtx.size() - 1; i >= 0; i--) { + const CTransaction &tx = vtx[i]; + uint256 hash = tx.GetHash(); + + // check that all outputs are available + if (!view.HaveCoins(hash)) { + fClean = fClean && error("DisconnectBlock() : outputs still spent? database corrupted"); + view.SetCoins(hash, CCoins()); + } + CCoins &outs = view.GetCoins(hash); + + CCoins outsBlock = CCoins(tx, pindex->nHeight); + // The CCoins serialization does not serialize negative numbers. + // No network rules currently depend on the version here, so an inconsistency is harmless + // but it must be corrected before txout nversion ever influences a network rule. + if (outsBlock.nVersion < 0) + outs.nVersion = outsBlock.nVersion; + if (outs != outsBlock) + fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted"); + + // remove outputs + outs = CCoins(); + + // 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"); + for (unsigned int j = tx.vin.size(); j-- > 0;) { + const COutPoint &out = tx.vin[j].prevout; + const CTxInUndo &undo = txundo.vprevout[j]; + CCoins coins; + view.GetCoins(out.hash, coins); // this can fail if the prevout was already entirely spent + if (undo.nHeight != 0) { + // undo data contains height: this is the last output of the prevout tx being spent + if (!coins.IsPruned()) + fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction"); + coins = CCoins(); + coins.fCoinBase = undo.fCoinBase; + coins.nHeight = undo.nHeight; + coins.nVersion = undo.nVersion; + } else { + if (coins.IsPruned()) + fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction"); + } + if (coins.IsAvailable(out.n)) + fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output"); + if (coins.vout.size() < out.n+1) + coins.vout.resize(out.n+1); + coins.vout[out.n] = undo.txout; + if (!view.SetCoins(out.hash, coins)) + return error("DisconnectBlock() : cannot restore coin inputs"); + } + } } - return true; + // move best block pointer to prevout block + view.SetBestBlock(pindex->pprev); + + if (pfClean) { + *pfClean = fClean; + return true; + } else { + return fClean; + } } -bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) +void static FlushBlockFile(bool fFinalize = false) +{ + LOCK(cs_LastBlockFile); + + CDiskBlockPos posOld(nLastBlockFile, 0); + + FILE *fileOld = OpenBlockFile(posOld); + if (fileOld) { + if (fFinalize) + TruncateFile(fileOld, infoLastBlockFile.nSize); + FileCommit(fileOld); + fclose(fileOld); + } + + fileOld = OpenUndoFile(posOld); + if (fileOld) { + if (fFinalize) + TruncateFile(fileOld, infoLastBlockFile.nUndoSize); + FileCommit(fileOld); + fclose(fileOld); + } +} + +bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize); + +static CCheckQueue scriptcheckqueue(128); + +void ThreadScriptCheck() { + RenameThread("bitcoin-scriptch"); + scriptcheckqueue.Thread(); +} + +bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!CheckBlock()) + if (!CheckBlock(state, !fJustCheck, !fJustCheck)) return false; + // verify that the view's current state corresponds to the previous block + assert(pindex->pprev == view.GetBestBlock()); + + // Special case for the genesis block, skipping connection of its transactions + // (its coinbase is unspendable) + if (GetHash() == hashGenesisBlock) { + view.SetBestBlock(pindex); + pindexGenesisBlock = pindex; + return true; + } + + bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(); + // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. // If such overwrites are allowed, coinbases and transactions depending upon those @@ -1382,166 +1755,235 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) // being sent to another address. // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information. // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool - // already refuses previously-known transaction id's entirely. - // This rule applies to all blocks whose timestamp is after October 1, 2012, 0:00 UTC. - int64 nBIP30SwitchTime = 1349049600; - bool fEnforceBIP30 = (pindex->nTime > nBIP30SwitchTime); + // already refuses previously-known transaction ids entirely. + // This rule was originally applied all blocks whose timestamp was after October 1, 2012, 0:00 UTC. + // Now that the whole chain is irreversibly beyond that time it is applied to all blocks, + // this prevents exploiting the issue against nodes in their initial block download. + bool fEnforceBIP30 = true; - // BIP16 didn't become active until October 1 2012 + if (fEnforceBIP30) { + for (unsigned int i=0; inTime >= nBIP16SwitchTime); - //// issue here: it doesn't know the version - unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size()); + unsigned int flags = SCRIPT_VERIFY_NOCACHE | + (fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE); - map mapQueuedChanges; + CBlockUndo blockundo; + + CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); + + int64 nStart = GetTimeMicros(); int64 nFees = 0; + int nInputs = 0; unsigned int nSigOps = 0; - BOOST_FOREACH(CTransaction& tx, vtx) + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size())); + std::vector > vPos; + vPos.reserve(vtx.size()); + for (unsigned int i=0; i MAX_BLOCK_SIGOPS) - return DoS(100, error("ConnectBlock() : too many sigops")); + return state.DoS(100, error("ConnectBlock() : too many sigops")); - CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); - nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); - - MapPrevTx mapInputs; if (!tx.IsCoinBase()) { - bool fInvalid; - if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid)) - return false; + if (!tx.HaveInputs(view)) + return state.DoS(100, error("ConnectBlock() : inputs missing/spent")); if (fStrictPayToScriptHash) { // Add in sigops done by pay-to-script-hash inputs; // this is to prevent a "rogue miner" from creating // an incredibly-expensive-to-validate block. - nSigOps += tx.GetP2SHSigOpCount(mapInputs); + nSigOps += tx.GetP2SHSigOpCount(view); if (nSigOps > MAX_BLOCK_SIGOPS) - return DoS(100, error("ConnectBlock() : too many sigops")); + return state.DoS(100, error("ConnectBlock() : too many sigops")); } - nFees += tx.GetValueIn(mapInputs)-tx.GetValueOut(); + nFees += tx.GetValueIn(view)-tx.GetValueOut(); - if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fStrictPayToScriptHash)) + std::vector vChecks; + if (!tx.CheckInputs(state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL)) return false; + control.Add(vChecks); } - mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size()); - } + CTxUndo txundo; + tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i)); + if (!tx.IsCoinBase()) + blockundo.vtxundo.push_back(txundo); - // Write queued txindex changes - for (map::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi) - { - if (!txdb.UpdateTxIndex((*mi).first, (*mi).second)) - return error("ConnectBlock() : UpdateTxIndex failed"); + vPos.push_back(std::make_pair(GetTxHash(i), pos)); + pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) - return false; + return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees))); - // Update block index on disk without changing it in memory. - // The memory index structure will be changed after the db commits. - if (pindex->pprev) + if (!control.Wait()) + return state.DoS(100, false); + int64 nTime2 = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Verify %u txins: %.2fms (%.3fms/txin)\n", nInputs - 1, 0.001 * nTime2, nInputs <= 1 ? 0 : 0.001 * nTime2 / (nInputs-1)); + + if (fJustCheck) + return true; + + // Write undo information to disk + if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) { - CDiskBlockIndex blockindexPrev(pindex->pprev); - blockindexPrev.hashNext = pindex->GetBlockHash(); - if (!txdb.WriteBlockIndex(blockindexPrev)) - return error("ConnectBlock() : WriteBlockIndex failed"); + if (pindex->GetUndoPos().IsNull()) { + CDiskBlockPos pos; + if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) + return error("ConnectBlock() : FindUndoPos failed"); + if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash())) + return state.Abort(_("Failed to write undo data")); + + // update nUndoPos in block index + pindex->nUndoPos = pos.nPos; + pindex->nStatus |= BLOCK_HAVE_UNDO; + } + + pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS; + + CDiskBlockIndex blockindex(pindex); + if (!pblocktree->WriteBlockIndex(blockindex)) + return state.Abort(_("Failed to write block index")); } + if (fTxIndex) + if (!pblocktree->WriteTxIndex(vPos)) + return state.Abort(_("Failed to write transaction index")); + + // add this block to the view's block chain + assert(view.SetBestBlock(pindex)); + // Watch for transactions paying to me - BOOST_FOREACH(CTransaction& tx, vtx) - SyncWithWallets(tx, this, true); + for (unsigned int i=0; inHeight > pfork->nHeight) - if (!(plonger = plonger->pprev)) - return error("Reorganize() : plonger->pprev is null"); + while (plonger->nHeight > pfork->nHeight) { + plonger = plonger->pprev; + assert(plonger != NULL); + } if (pfork == plonger) break; - if (!(pfork = pfork->pprev)) - return error("Reorganize() : pfork->pprev is null"); + pfork = pfork->pprev; + assert(pfork != NULL); } - // List of what to disconnect + // List of what to disconnect (typically nothing) vector vDisconnect; - for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev) + for (CBlockIndex* pindex = view.GetBestBlock(); pindex != pfork; pindex = pindex->pprev) vDisconnect.push_back(pindex); - // List of what to connect + // List of what to connect (typically only pindexNew) vector vConnect; for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev) vConnect.push_back(pindex); reverse(vConnect.begin(), vConnect.end()); - printf("REORGANIZE: Disconnect %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); - printf("REORGANIZE: Connect %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + if (vDisconnect.size() > 0) { + printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..\n", vDisconnect.size(), pfork->GetBlockHash().ToString().c_str()); + printf("REORGANIZE: Connect %"PRIszu" blocks; ..%s\n", vConnect.size(), pindexNew->GetBlockHash().ToString().c_str()); + } // Disconnect shorter branch vector vResurrect; - BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) - { + BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { CBlock block; if (!block.ReadFromDisk(pindex)) - return error("Reorganize() : ReadFromDisk for disconnect failed"); - if (!block.DisconnectBlock(txdb, pindex)) - return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); + return state.Abort(_("Failed to read block")); + int64 nStart = GetTimeMicros(); + if (!block.DisconnectBlock(state, pindex, view)) + return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); + if (fBenchmark) + printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); - // Queue memory transactions to resurrect + // Queue memory transactions to resurrect. + // We only do this for blocks after the last checkpoint (reorganisation before that + // point should only happen with -reindex/-loadblock, or a misbehaving peer. BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!tx.IsCoinBase()) + if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate()) vResurrect.push_back(tx); } // Connect longer branch vector vDelete; - for (unsigned int i = 0; i < vConnect.size(); i++) - { - CBlockIndex* pindex = vConnect[i]; + BOOST_FOREACH(CBlockIndex *pindex, vConnect) { CBlock block; if (!block.ReadFromDisk(pindex)) - return error("Reorganize() : ReadFromDisk for connect failed"); - if (!block.ConnectBlock(txdb, pindex)) - { - // Invalid block - return error("Reorganize() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); + return state.Abort(_("Failed to read block")); + int64 nStart = GetTimeMicros(); + if (!block.ConnectBlock(state, pindex, view)) { + if (state.IsInvalid()) { + InvalidChainFound(pindexNew); + InvalidBlockFound(pindex); + } + return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); } + if (fBenchmark) + printf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); // Queue memory transactions to delete BOOST_FOREACH(const CTransaction& tx, block.vtx) vDelete.push_back(tx); } - if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash())) - return error("Reorganize() : WriteHashBestChain failed"); + + // Flush changes to global coin state + int64 nStart = GetTimeMicros(); + int nModified = view.GetCacheSize(); + assert(view.Flush()); + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified); // Make sure it's successfully written to disk before changing memory structure - if (!txdb.TxnCommit()) - return error("Reorganize() : TxnCommit failed"); + bool fIsInitialDownload = IsInitialBlockDownload(); + if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) { + // Typical CCoins structures on disk are around 100 bytes in size. + // Pushing a new one to the database can cause it to be written + // twice (once in the log, and once in the tables). This is already + // an overestimation, as most will delete an existing entry or + // overwrite one. Still, use a conservative safety factor of 2. + if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize())) + return state.Error(); + FlushBlockFile(); + pblocktree->Sync(); + if (!pcoinsTip->Flush()) + return state.Abort(_("Failed to write to coin database")); + } + + // At this point, all changes have been done to the database. + // Proceed by updating the memory structures. // Disconnect shorter branch BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) @@ -1554,127 +1996,38 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) pindex->pprev->pnext = pindex; // Resurrect memory transactions that were in the disconnected branch - BOOST_FOREACH(CTransaction& tx, vResurrect) - tx.AcceptToMemoryPool(txdb, false); + BOOST_FOREACH(CTransaction& tx, vResurrect) { + // ignore validation errors in resurrected transactions + CValidationState stateDummy; + if (!tx.AcceptToMemoryPool(stateDummy, true, false)) + mempool.remove(tx, true); + } // Delete redundant memory transactions that are in the connected branch - BOOST_FOREACH(CTransaction& tx, vDelete) + BOOST_FOREACH(CTransaction& tx, vDelete) { mempool.remove(tx); - - printf("REORGANIZE: done\n"); - - return true; -} - - -// Called from inside SetBestChain: attaches a block to the new best chain being built -bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew) -{ - uint256 hash = GetHash(); - - // Adding to current best branch - if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) - { - txdb.TxnAbort(); - InvalidChainFound(pindexNew); - return false; - } - if (!txdb.TxnCommit()) - return error("SetBestChain() : TxnCommit failed"); - - // Add to current best branch - pindexNew->pprev->pnext = pindexNew; - - // Delete redundant memory transactions - BOOST_FOREACH(CTransaction& tx, vtx) - mempool.remove(tx); - - return true; -} - -bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) -{ - uint256 hash = GetHash(); - - if (!txdb.TxnBegin()) - return error("SetBestChain() : TxnBegin failed"); - - if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) - { - txdb.WriteHashBestChain(hash); - if (!txdb.TxnCommit()) - return error("SetBestChain() : TxnCommit failed"); - pindexGenesisBlock = pindexNew; - } - else if (hashPrevBlock == hashBestChain) - { - if (!SetBestChainInner(txdb, pindexNew)) - return error("SetBestChain() : SetBestChainInner failed"); - } - else - { - // the first block in the new chain that will cause it to become the new best chain - CBlockIndex *pindexIntermediate = pindexNew; - - // list of blocks that need to be connected afterwards - std::vector vpindexSecondary; - - // Reorganize is costly in terms of db load, as it works in a single db transaction. - // Try to limit how much needs to be done inside - while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork) - { - vpindexSecondary.push_back(pindexIntermediate); - pindexIntermediate = pindexIntermediate->pprev; - } - - if (!vpindexSecondary.empty()) - printf("Postponing %i reconnects\n", vpindexSecondary.size()); - - // Switch to new best branch - if (!Reorganize(txdb, pindexIntermediate)) - { - txdb.TxnAbort(); - InvalidChainFound(pindexNew); - return error("SetBestChain() : Reorganize failed"); - } - - // Connect futher blocks - BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary) - { - CBlock block; - if (!block.ReadFromDisk(pindex)) - { - printf("SetBestChain() : ReadFromDisk failed\n"); - break; - } - if (!txdb.TxnBegin()) { - printf("SetBestChain() : TxnBegin 2 failed\n"); - break; - } - // errors now are not fatal, we still did a reorganisation to a new chain in a valid way - if (!block.SetBestChainInner(txdb, pindex)) - break; - } + mempool.removeConflicts(tx); } // Update best block in wallet (so we can detect restored wallets) - bool fIsInitialDownload = IsInitialBlockDownload(); - if (!fIsInitialDownload) + if ((pindexNew->nHeight % 7200) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) { const CBlockLocator locator(pindexNew); ::SetBestChain(locator); } // New best block - hashBestChain = hash; + hashBestChain = pindexNew->GetBlockHash(); pindexBest = pindexNew; + pblockindexFBBHLast = NULL; nBestHeight = pindexBest->nHeight; - bnBestChainWork = pindexNew->bnChainWork; + nBestChainWork = pindexNew->nChainWork; nTimeBestReceived = GetTime(); nTransactionsUpdated++; - printf("SetBestChain: new best=%s height=%d work=%s date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), - DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + printf("SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n", + hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str(), + Checkpoints::GuessVerificationProgress(pindexBest)); // Check the version of the last 100 blocks to see if we need to upgrade: if (!fIsInitialDownload) @@ -1689,9 +2042,9 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } if (nUpgraded > 0) printf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION); - // if (nUpgraded > 100/2) + if (nUpgraded > 100/2) // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - // strMiscWarning = _("Warning: this version is obsolete, upgrade required"); + strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); } std::string strCmd = GetArg("-blocknotify", ""); @@ -1706,17 +2059,16 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } -bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) +bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) { // Check for duplicate uint256 hash = GetHash(); if (mapBlockIndex.count(hash)) - return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str()); + return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str())); // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); - if (!pindexNew) - return error("AddToBlockIndex() : new CBlockIndex failed"); + CBlockIndex* pindexNew = new CBlockIndex(*this); + assert(pindexNew); map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); map::iterator miPrev = mapBlockIndex.find(hashPrevBlock); @@ -1725,75 +2077,175 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork(); + pindexNew->nTx = vtx.size(); + pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); + pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; + pindexNew->nFile = pos.nFile; + pindexNew->nDataPos = pos.nPos; + pindexNew->nUndoPos = 0; + pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA; + setBlockIndexValid.insert(pindexNew); - CTxDB txdb; - if (!txdb.TxnBegin()) + if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew))) + return state.Abort(_("Failed to write block index")); + + // New best? + if (!ConnectBestBlock(state)) return false; - txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); - if (!txdb.TxnCommit()) - return false; - - // New best - if (pindexNew->bnChainWork > bnBestChainWork) - if (!SetBestChain(txdb, pindexNew)) - return false; - - txdb.Close(); if (pindexNew == pindexBest) { // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = vtx[0].GetHash(); + hashPrevBestCoinBase = GetTxHash(0); } + if (!pblocktree->Flush()) + return state.Abort(_("Failed to sync block index")); + uiInterface.NotifyBlocksChanged(); return true; } +bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime, bool fKnown = false) +{ + bool fUpdatedLast = false; + + LOCK(cs_LastBlockFile); + + if (fKnown) { + if (nLastBlockFile != pos.nFile) { + nLastBlockFile = pos.nFile; + infoLastBlockFile.SetNull(); + pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); + fUpdatedLast = true; + } + } else { + while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { + printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str()); + FlushBlockFile(true); + nLastBlockFile++; + infoLastBlockFile.SetNull(); + pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine + fUpdatedLast = true; + } + pos.nFile = nLastBlockFile; + pos.nPos = infoLastBlockFile.nSize; + } + + infoLastBlockFile.nSize += nAddSize; + infoLastBlockFile.AddBlock(nHeight, nTime); + + if (!fKnown) { + unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; + unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; + if (nNewChunks > nOldChunks) { + if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenBlockFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } + } + else + return state.Error(); + } + } + + if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) + return state.Abort(_("Failed to write file info")); + if (fUpdatedLast) + pblocktree->WriteLastBlockFile(nLastBlockFile); + + return true; +} + +bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) +{ + pos.nFile = nFile; + + LOCK(cs_LastBlockFile); + + unsigned int nNewSize; + if (nFile == nLastBlockFile) { + pos.nPos = infoLastBlockFile.nUndoSize; + nNewSize = (infoLastBlockFile.nUndoSize += nAddSize); + if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) + return state.Abort(_("Failed to write block info")); + } else { + CBlockFileInfo info; + if (!pblocktree->ReadBlockFileInfo(nFile, info)) + return state.Abort(_("Failed to read block info")); + pos.nPos = info.nUndoSize; + nNewSize = (info.nUndoSize += nAddSize); + if (!pblocktree->WriteBlockFileInfo(nFile, info)) + return state.Abort(_("Failed to write block info")); + } + + unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; + unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; + if (nNewChunks > nOldChunks) { + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenUndoFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } + } + else + return state.Error(); + } + + return true; +} -bool CBlock::CheckBlock() const +bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const { // These are checks that are independent of context // that can be verified before saving an orphan block. // Size limits if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return DoS(100, error("CheckBlock() : size limits failed")); + return state.DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount - if (!CheckProofOfWork(GetPoWHash(), nBits)) - return DoS(50, error("CheckBlock() : proof of work failed")); + if (fCheckPOW && !CheckProofOfWork(GetPoWHash(), nBits)) + return state.DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) - return error("CheckBlock() : block timestamp too far in the future"); + return state.Invalid(error("CheckBlock() : block timestamp too far in the future")); // First transaction must be coinbase, the rest must not be if (vtx.empty() || !vtx[0].IsCoinBase()) - return DoS(100, error("CheckBlock() : first tx is not coinbase")); + return state.DoS(100, error("CheckBlock() : first tx is not coinbase")); for (unsigned int i = 1; i < vtx.size(); i++) if (vtx[i].IsCoinBase()) - return DoS(100, error("CheckBlock() : more than one coinbase")); + return state.DoS(100, error("CheckBlock() : more than one coinbase")); // Check transactions BOOST_FOREACH(const CTransaction& tx, vtx) - if (!tx.CheckTransaction()) - return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); + if (!tx.CheckTransaction(state)) + return error("CheckBlock() : CheckTransaction failed"); + + // Build the merkle tree already. We need it anyway later, and it makes the + // block cache the transaction hashes, which means they don't need to be + // recalculated many times during this block's validation. + BuildMerkleTree(); // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: set uniqueTx; - BOOST_FOREACH(const CTransaction& tx, vtx) - { - uniqueTx.insert(tx.GetHash()); + for (unsigned int i=0; i MAX_BLOCK_SIGOPS) - return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); + return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); - // Check merkleroot - if (hashMerkleRoot != BuildMerkleTree()) - return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); + // Check merkle root + if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) + return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); return true; } -bool CBlock::AcceptBlock() +bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) { // Check for duplicate uint256 hash = GetHash(); if (mapBlockIndex.count(hash)) - return error("AcceptBlock() : block already in mapBlockIndex"); + return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex")); // Get prev block index - map::iterator mi = mapBlockIndex.find(hashPrevBlock); - if (mi == mapBlockIndex.end()) - return DoS(10, error("AcceptBlock() : prev block not found")); - CBlockIndex* pindexPrev = (*mi).second; - int nHeight = pindexPrev->nHeight+1; + CBlockIndex* pindexPrev = NULL; + int nHeight = 0; + if (hash != hashGenesisBlock) { + map::iterator mi = mapBlockIndex.find(hashPrevBlock); + if (mi == mapBlockIndex.end()) + return state.DoS(10, error("AcceptBlock() : prev block not found")); + pindexPrev = (*mi).second; + nHeight = pindexPrev->nHeight+1; - // Check proof of work - if (nBits != GetNextWorkRequired(pindexPrev, this)) - return DoS(100, error("AcceptBlock() : incorrect proof of work")); + // Check proof of work + if (nBits != GetNextWorkRequired(pindexPrev, this)) + return state.DoS(100, error("AcceptBlock() : incorrect proof of work")); - // Check timestamp against prev - if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return error("AcceptBlock() : block's timestamp is too early"); + // Check timestamp against prev + if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) + return state.Invalid(error("AcceptBlock() : block's timestamp is too early")); - // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, vtx) - if (!tx.IsFinal(nHeight, GetBlockTime())) - return DoS(10, error("AcceptBlock() : contains a non-final transaction")); + // Check that all transactions are finalized + BOOST_FOREACH(const CTransaction& tx, vtx) + if (!tx.IsFinal(nHeight, GetBlockTime())) + return state.DoS(10, error("AcceptBlock() : contains a non-final transaction")); - // Check that the block chain matches the known block chain up to a checkpoint - if (!Checkpoints::CheckBlock(nHeight, hash)) - return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight)); + // Check that the block chain matches the known block chain up to a checkpoint + if (!Checkpoints::CheckBlock(nHeight, hash)) + return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); + + // Don't accept any forks from the main chain prior to last checkpoint + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); + if (pcheckpoint && nHeight < pcheckpoint->nHeight) + return state.DoS(100, error("AcceptBlock() : forked chain older than last checkpoint (height %d)", nHeight)); + + // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: + if (nVersion < 2) + { + if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || + (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) + { + return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block")); + } + } + // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height + if (nVersion >= 2) + { + // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): + if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || + (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) + { + CScript expect = CScript() << nHeight; + if (vtx[0].vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); + } + } + } // Write block to history file - if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) - return error("AcceptBlock() : out of disk space"); - unsigned int nFile = -1; - unsigned int nBlockPos = 0; - if (!WriteToDisk(nFile, nBlockPos)) - return error("AcceptBlock() : WriteToDisk failed"); - if (!AddToBlockIndex(nFile, nBlockPos)) - return error("AcceptBlock() : AddToBlockIndex failed"); + try { + unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + if (dbp != NULL) + blockPos = *dbp; + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) + return error("AcceptBlock() : FindBlockPos failed"); + if (dbp == NULL) + if (!WriteToDisk(blockPos)) + return state.Abort(_("Failed to write block")); + if (!AddToBlockIndex(state, blockPos)) + return error("AcceptBlock() : AddToBlockIndex failed"); + } catch(std::runtime_error &e) { + return state.Abort(_("System error: ") + e.what()); + } // Relay inventory, but don't relay old inventory during initial block download int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); @@ -1864,17 +2355,31 @@ bool CBlock::AcceptBlock() return true; } -bool ProcessBlock(CNode* pfrom, CBlock* pblock) +bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck) +{ + // CasinoCoin: temporarily disable v2 block lockin until we are ready for v2 transition + return false; + unsigned int nFound = 0; + for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + return (nFound >= nRequired); +} + +bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) { // Check for duplicate uint256 hash = pblock->GetHash(); if (mapBlockIndex.count(hash)) - return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str()); + return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().c_str())); if (mapOrphanBlocks.count(hash)) - return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str()); + return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str())); // Preliminary checks - if (!pblock->CheckBlock()) + if (!pblock->CheckBlock(state)) return error("ProcessBlock() : CheckBlock FAILED"); CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); @@ -1884,9 +2389,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; if (deltaTime < 0) { - if (pfrom) - pfrom->Misbehaving(100); - return error("ProcessBlock() : block with timestamp before last checkpoint"); + return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint")); } CBigNum bnNewBlock; bnNewBlock.SetCompact(pblock->nBits); @@ -1894,29 +2397,30 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); if (bnNewBlock > bnRequired) { - if (pfrom) - pfrom->Misbehaving(100); - return error("ProcessBlock() : block with too little proof-of-work"); + return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work")); } } - // If don't already have its previous block, shunt it off to holding area until we get it - if (!mapBlockIndex.count(pblock->hashPrevBlock)) + // If we don't already have its previous block, shunt it off to holding area until we get it + if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock)) { - printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); - CBlock* pblock2 = new CBlock(*pblock); - mapOrphanBlocks.insert(make_pair(hash, pblock2)); - mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); + printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().c_str()); - // Ask this guy to fill in what we're missing - if (pfrom) + // Accept orphans as long as there is a node to request its parents from + if (pfrom) { + CBlock* pblock2 = new CBlock(*pblock); + mapOrphanBlocks.insert(make_pair(hash, pblock2)); + mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); + + // Ask this guy to fill in what we're missing pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2)); + } return true; } // Store to disk - if (!pblock->AcceptBlock()) + if (!pblock->AcceptBlock(state, dbp)) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -1930,7 +2434,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) ++mi) { CBlock* pblockOrphan = (*mi).second; - if (pblockOrphan->AcceptBlock()) + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) + CValidationState stateDummy; + if (pblockOrphan->AcceptBlock(stateDummy)) vWorkQueue.push_back(pblockOrphan->GetHash()); mapOrphanBlocks.erase(pblockOrphan->GetHash()); delete pblockOrphan; @@ -1949,35 +2455,198 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) +CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) +{ + header = block.GetBlockHeader(); + + vector vMatch; + vector vHashes; + + vMatch.reserve(block.vtx.size()); + vHashes.reserve(block.vtx.size()); + + for (unsigned int i = 0; i < block.vtx.size(); i++) + { + uint256 hash = block.vtx[i].GetHash(); + if (filter.IsRelevantAndUpdate(block.vtx[i], hash)) + { + vMatch.push_back(true); + vMatchedTxn.push_back(make_pair(i, hash)); + } + else + vMatch.push_back(false); + vHashes.push_back(hash); + } + + txn = CPartialMerkleTree(vHashes, vMatch); +} + + + + + + + + +uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector &vTxid) { + if (height == 0) { + // hash at height 0 is the txids themself + return vTxid[pos]; + } else { + // calculate left hash + uint256 left = CalcHash(height-1, pos*2, vTxid), right; + // calculate right hash if not beyong the end of the array - copy left hash otherwise1 + if (pos*2+1 < CalcTreeWidth(height-1)) + right = CalcHash(height-1, pos*2+1, vTxid); + else + right = left; + // combine subhashes + return Hash(BEGIN(left), END(left), BEGIN(right), END(right)); + } +} + +void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector &vTxid, const std::vector &vMatch) { + // determine whether this node is the parent of at least one matched txid + bool fParentOfMatch = false; + for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++) + fParentOfMatch |= vMatch[p]; + // store as flag bit + vBits.push_back(fParentOfMatch); + if (height==0 || !fParentOfMatch) { + // if at height 0, or nothing interesting below, store hash and stop + vHash.push_back(CalcHash(height, pos, vTxid)); + } else { + // otherwise, don't store any hash, but descend into the subtrees + TraverseAndBuild(height-1, pos*2, vTxid, vMatch); + if (pos*2+1 < CalcTreeWidth(height-1)) + TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch); + } +} + +uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch) { + if (nBitsUsed >= vBits.size()) { + // overflowed the bits array - failure + fBad = true; + return 0; + } + bool fParentOfMatch = vBits[nBitsUsed++]; + if (height==0 || !fParentOfMatch) { + // if at height 0, or nothing interesting below, use stored hash and do not descend + if (nHashUsed >= vHash.size()) { + // overflowed the hash array - failure + fBad = true; + return 0; + } + const uint256 &hash = vHash[nHashUsed++]; + if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid + vMatch.push_back(hash); + return hash; + } else { + // otherwise, descend into the subtrees to extract matched txids and hashes + uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right; + if (pos*2+1 < CalcTreeWidth(height-1)) + right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch); + else + right = left; + // and combine them before returning + return Hash(BEGIN(left), END(left), BEGIN(right), END(right)); + } +} + +CPartialMerkleTree::CPartialMerkleTree(const std::vector &vTxid, const std::vector &vMatch) : nTransactions(vTxid.size()), fBad(false) { + // reset state + vBits.clear(); + vHash.clear(); + + // calculate height of tree + int nHeight = 0; + while (CalcTreeWidth(nHeight) > 1) + nHeight++; + + // traverse the partial tree + TraverseAndBuild(nHeight, 0, vTxid, vMatch); +} + +CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {} + +uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch) { + vMatch.clear(); + // An empty set will not work + if (nTransactions == 0) + return 0; + // check for excessively high numbers of transactions + if (nTransactions > MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction + return 0; + // there can never be more hashes provided than one for every txid + if (vHash.size() > nTransactions) + return 0; + // there must be at least one bit per node in the partial tree, and at least one node per hash + if (vBits.size() < vHash.size()) + return 0; + // calculate height of tree + int nHeight = 0; + while (CalcTreeWidth(nHeight) > 1) + nHeight++; + // traverse the partial tree + unsigned int nBitsUsed = 0, nHashUsed = 0; + uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch); + // verify that no problems occured during the tree traversal + if (fBad) + return 0; + // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence) + if ((nBitsUsed+7)/8 != (vBits.size()+7)/8) + return 0; + // verify that all hashes were consumed + if (nHashUsed != vHash.size()) + return 0; + return hashMerkleRoot; +} + + + + + + + +bool AbortNode(const std::string &strMessage) { + strMiscWarning = strMessage; + printf("*** %s\n", strMessage.c_str()); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; +} + bool CheckDiskSpace(uint64 nAdditionalBytes) { uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available; // Check for nMinDiskSpace bytes (currently 50MB) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) - { - fShutdown = true; - string strMessage = _("Warning: Disk space is low"); - strMiscWarning = strMessage; - printf("*** %s\n", strMessage.c_str()); - uiInterface.ThreadSafeMessageBox(strMessage, "CasinoCoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); - StartShutdown(); - return false; - } + return AbortNode(_("Error: Disk space is low!")); + return true; } -FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode) +CCriticalSection cs_LastBlockFile; +CBlockFileInfo infoLastBlockFile; +int nLastBlockFile = 0; + +FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) { - if ((nFile < 1) || (nFile == (unsigned int) -1)) + if (pos.IsNull()) return NULL; - FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode); - if (!file) + boost::filesystem::path path = GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); + boost::filesystem::create_directories(path.parent_path()); + FILE* file = fopen(path.string().c_str(), "rb+"); + if (!file && !fReadOnly) + file = fopen(path.string().c_str(), "wb+"); + if (!file) { + printf("Unable to open file %s\n", path.string().c_str()); return NULL; - if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) - { - if (fseek(file, nBlockPos, SEEK_SET) != 0) - { + } + if (pos.nPos) { + if (fseek(file, pos.nPos, SEEK_SET)) { + printf("Unable to seek to position %u of %s\n", pos.nPos, path.string().c_str()); fclose(file); return NULL; } @@ -1985,30 +2654,187 @@ FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszM return file; } -static unsigned int nCurrentBlockFile = 1; - -FILE* AppendBlockFile(unsigned int& nFileRet) -{ - nFileRet = 0; - loop - { - FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab"); - if (!file) - return NULL; - if (fseek(file, 0, SEEK_END) != 0) - return NULL; - // FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB - if (ftell(file) < 0x7F000000 - MAX_SIZE) - { - nFileRet = nCurrentBlockFile; - return file; - } - fclose(file); - nCurrentBlockFile++; - } +FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { + return OpenDiskFile(pos, "blk", fReadOnly); } -bool LoadBlockIndex(bool fAllowNew) +FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { + return OpenDiskFile(pos, "rev", fReadOnly); +} + +CBlockIndex * InsertBlockIndex(uint256 hash) +{ + if (hash == 0) + return NULL; + + // Return existing + map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + return (*mi).second; + + // Create new + CBlockIndex* pindexNew = new CBlockIndex(); + if (!pindexNew) + throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); + mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + + return pindexNew; +} + +bool static LoadBlockIndexDB() +{ + if (!pblocktree->LoadBlockIndexGuts()) + return false; + + boost::this_thread::interruption_point(); + + // Calculate nChainWork + vector > 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)); + } + 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) + pindex->GetBlockWork().getuint256(); + pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; + if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK)) + setBlockIndexValid.insert(pindex); + } + + // Load block file info + pblocktree->ReadLastBlockFile(nLastBlockFile); + printf("LoadBlockIndexDB(): last block file = %i\n", nLastBlockFile); + if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile)) + printf("LoadBlockIndexDB(): last block file info: %s\n", infoLastBlockFile.ToString().c_str()); + + // Load nBestInvalidWork, OK if it doesn't exist + CBigNum bnBestInvalidWork; + pblocktree->ReadBestInvalidWork(bnBestInvalidWork); + nBestInvalidWork = bnBestInvalidWork.getuint256(); + + // Check whether we need to continue reindexing + bool fReindexing = false; + pblocktree->ReadReindexing(fReindexing); + fReindex |= fReindexing; + + // Check whether we have a transaction index + pblocktree->ReadFlag("txindex", fTxIndex); + printf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled"); + + // Load hashBestChain pointer to end of best chain + pindexBest = pcoinsTip->GetBestBlock(); + if (pindexBest == NULL) + return true; + hashBestChain = pindexBest->GetBlockHash(); + nBestHeight = pindexBest->nHeight; + nBestChainWork = pindexBest->nChainWork; + + // set 'next' pointers in best chain + CBlockIndex *pindex = pindexBest; + while(pindex != NULL && pindex->pprev != NULL) { + CBlockIndex *pindexPrev = pindex->pprev; + pindexPrev->pnext = pindex; + pindex = pindexPrev; + } + printf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n", + hashBestChain.ToString().c_str(), nBestHeight, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + + return true; +} + +bool VerifyDB(int nCheckLevel, int nCheckDepth) +{ + if (pindexBest == NULL || pindexBest->pprev == NULL) + return true; + + // Verify blocks in the best chain + if (nCheckDepth <= 0) + nCheckDepth = 1000000000; // suffices until the year 19000 + if (nCheckDepth > nBestHeight) + nCheckDepth = nBestHeight; + nCheckLevel = std::max(0, std::min(4, nCheckLevel)); + printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); + CCoinsViewCache coins(*pcoinsTip, true); + CBlockIndex* pindexState = pindexBest; + CBlockIndex* pindexFailure = NULL; + int nGoodTransactions = 0; + CValidationState state; + for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) + { + boost::this_thread::interruption_point(); + if (pindex->nHeight < nBestHeight-nCheckDepth) + break; + CBlock block; + // check level 0: read from disk + if (!block.ReadFromDisk(pindex)) + return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + // check level 1: verify block validity + if (nCheckLevel >= 1 && !block.CheckBlock(state)) + return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + // check level 2: verify undo validity + if (nCheckLevel >= 2 && pindex) { + CBlockUndo undo; + CDiskBlockPos pos = pindex->GetUndoPos(); + if (!pos.IsNull()) { + if (!undo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) + return error("VerifyDB() : *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + } + } + // check level 3: check for inconsistencies during memory-only disconnect of tip blocks + if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) { + bool fClean = true; + if (!block.DisconnectBlock(state, pindex, coins, &fClean)) + return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + pindexState = pindex->pprev; + if (!fClean) { + nGoodTransactions = 0; + pindexFailure = pindex; + } else + nGoodTransactions += block.vtx.size(); + } + } + if (pindexFailure) + return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", pindexBest->nHeight - pindexFailure->nHeight + 1, nGoodTransactions); + + // check level 4: try reconnecting blocks + if (nCheckLevel >= 4) { + CBlockIndex *pindex = pindexState; + while (pindex != pindexBest) { + boost::this_thread::interruption_point(); + pindex = pindex->pnext; + CBlock block; + if (!block.ReadFromDisk(pindex)) + return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!block.ConnectBlock(state, pindex, coins)) + return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + } + } + + printf("No coin database inconsistencies in last %i blocks (%i transactions)\n", pindexBest->nHeight - pindexState->nHeight, nGoodTransactions); + + return true; +} + +void UnloadBlockIndex() +{ + mapBlockIndex.clear(); + setBlockIndexValid.clear(); + pindexGenesisBlock = NULL; + nBestHeight = 0; + nBestChainWork = 0; + nBestInvalidWork = 0; + hashBestChain = 0; + pindexBest = NULL; +} + +bool LoadBlockIndex() { if (fTestNet) { @@ -2016,25 +2842,31 @@ bool LoadBlockIndex(bool fAllowNew) pchMessageStart[1] = 0xc1; pchMessageStart[2] = 0xb7; pchMessageStart[3] = 0xdc; - hashGenesisBlock = uint256("0xe5d98005cd7744147b4c472fffc04a81bdc04756ddbcb49e6675f01b1585c1d3"); + hashGenesisBlock = uint256("0x60cf36f96baf1c3d882c9f155ee3dfc3a1cb5a47071d797f606714db54f4b5e8"); } // - // Load block index + // Load block index from databases // - CTxDB txdb("cr"); - if (!txdb.LoadBlockIndex()) + if (!fReindex && !LoadBlockIndexDB()) return false; - txdb.Close(); - // - // Init with genesis block - // - if (mapBlockIndex.empty()) - { - if (!fAllowNew) - return false; + return true; +} + +bool InitBlockIndex() { + // Check whether we're already initialized + if (pindexGenesisBlock != NULL) + return true; + + // Use the provided setting for -txindex in the new database + fTxIndex = GetBoolArg("-txindex", false); + pblocktree->WriteFlag("txindex", fTxIndex); + printf("Initializing databases...\n"); + + // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) + if (!fReindex) { // Genesis Block: // block.nTime = 1372621620 // block.nNonce = 1022795 @@ -2045,6 +2877,16 @@ bool LoadBlockIndex(bool fAllowNew) // CTxOut(error) // vMerkleTree: 2ae9af367b + // Testnet Genesis Block: + // 2014-02-09 14:28:11 block.nTime = 1391929777 + // 2014-02-09 14:28:11 block.nNonce = 873544 + // 2014-02-09 14:28:11 block.GetHash = 60cf36f96baf1c3d882c9f155ee3dfc3a1cb5a47071d797f606714db54f4b5e8 + // 2014-02-09 14:28:11 CBlock(hash=60cf36f96baf1c3d882c9f155ee3dfc3a1cb5a47071d797f606714db54f4b5e8, input=010000000000000000000000000000000000000000000000000000000000000000000000e623301387da4ba03a489e88193991a37aec5d30870f3c9150f165cade04d373b129f752ffff0f1e48540d00, PoW=000001093e70f341fdd06ad5649020e2d52e984ed6e720f4385ef4d944481c43, ver=1, hashPrevBlock=0000000000000000000000000000000000000000000000000000000000000000, hashMerkleRoot=73d304deca65f150913c0f87305dec7aa3913919889e483aa04bda87133023e6, nTime=1391929777, nBits=1e0fffff, nNonce=873544, vtx=1) + // 2014-02-09 14:28:11 CTransaction(hash=73d304deca65f150913c0f87305dec7aa3913919889e483aa04bda87133023e6, ver=1, vin.size=1, vout.size=1, nLockTime=0) + // CTxIn(COutPoint(0000000000000000000000000000000000000000000000000000000000000000, 4294967295), coinbase 04ffff001d0104344e592054696d657320322f4a756c792f32303133205768617420746865204e2e532e412e204b6e6f77732041626f757420596f75) + // CTxOut(error) + // vMerkleTree: 73d304deca65f150913c0f87305dec7aa3913919889e483aa04bda87133023e6 + // Genesis block const char* pszTimestamp = "NY Times 2/July/2013 What the N.S.A. Knows About You"; CTransaction txNew; @@ -2064,57 +2906,69 @@ bool LoadBlockIndex(bool fAllowNew) if (fTestNet) { - block.nTime = 1372621620; - block.nNonce = 1022795; + block.nBits = 0x1e0fffff; + block.nTime = 1391929777; + block.nNonce = 873544; } //// debug print - printf("%s\n", block.GetHash().ToString().c_str()); + uint256 hash = block.GetHash(); + printf("%s\n", hash.ToString().c_str()); printf("%s\n", hashGenesisBlock.ToString().c_str()); printf("%s\n", block.hashMerkleRoot.ToString().c_str()); + printf("min nBit: %08x\n", bnProofOfWorkLimit.GetCompact()); // added assert(block.hashMerkleRoot == uint256("0x73d304deca65f150913c0f87305dec7aa3913919889e483aa04bda87133023e6")); + // S: generate hash block // If genesis block hash does not match, then generate new genesis hash. - if (false && block.GetHash() != hashGenesisBlock) - { - printf("Searching for genesis block...\n"); - // This will figure out a valid hash and Nonce if you're - // creating a different genesis block: - uint256 hashTarget = CBigNum().SetCompact(block.nBits).getuint256(); - uint256 thash; - char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; - - loop - { - scrypt_1024_1_1_256_sp(BEGIN(block.nVersion), BEGIN(thash), scratchpad); - if (thash <= hashTarget) - break; - if ((block.nNonce & 0xFFF) == 0) - { - printf("nonce %08X: hash = %s (target = %s)\n", block.nNonce, thash.ToString().c_str(), hashTarget.ToString().c_str()); - } - ++block.nNonce; - if (block.nNonce == 0) - { - printf("NONCE WRAPPED, incrementing time\n"); - ++block.nTime; - } - } - printf("block.nTime = %u \n", block.nTime); - printf("block.nNonce = %u \n", block.nNonce); - printf("block.GetHash = %s\n", block.GetHash().ToString().c_str()); - } +// if (true && block.GetHash() != hashGenesisBlock) +// { +// printf("Searching for genesis block...\n"); +// // This will figure out a valid hash and Nonce if you're +// // creating a different genesis block: +// uint256 hashTarget = CBigNum().SetCompact(block.nBits).getuint256(); +// uint256 thash; +// char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; +// +// loop +// { +// scrypt_1024_1_1_256_sp(BEGIN(block.nVersion), BEGIN(thash), scratchpad); +// if (thash <= hashTarget) +// break; +// if ((block.nNonce & 0xFFF) == 0) +// { +// printf("nonce %08X: hash = %s (target = %s)\n", block.nNonce, thash.ToString().c_str(), hashTarget.ToString().c_str()); +// } +// ++block.nNonce; +// if (block.nNonce == 0) +// { +// printf("NONCE WRAPPED, incrementing time\n"); +// ++block.nTime; +// } +// } +// printf("block.nTime = %u \n", block.nTime); +// printf("block.nNonce = %u \n", block.nNonce); +// printf("block.GetHash = %s\n", block.GetHash().ToString().c_str()); +// } + // E: generate hash block block.print(); - assert(block.GetHash() == hashGenesisBlock); + assert(hash == hashGenesisBlock); // Start new block file - unsigned int nFile; - unsigned int nBlockPos; - if (!block.WriteToDisk(nFile, nBlockPos)) - return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!block.AddToBlockIndex(nFile, nBlockPos)) - return error("LoadBlockIndex() : genesis block not accepted"); + try { + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + CValidationState state; + if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) + return error("LoadBlockIndex() : FindBlockPos failed"); + if (!block.WriteToDisk(blockPos)) + return error("LoadBlockIndex() : writing genesis block to disk failed"); + if (!block.AddToBlockIndex(state, blockPos)) + return error("LoadBlockIndex() : genesis block not accepted"); + } catch(std::runtime_error &e) { + return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); + } } return true; @@ -2124,7 +2978,7 @@ bool LoadBlockIndex(bool fAllowNew) void PrintBlockTree() { - // precompute tree structure + // pre-compute tree structure map > mapNext; for (map::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) { @@ -2167,17 +3021,15 @@ void PrintBlockTree() // print item CBlock block; block.ReadFromDisk(pindex); - printf("%d (%u,%u) %s %s tx %d", + printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"", pindex->nHeight, - pindex->nFile, - pindex->nBlockPos, - block.GetHash().ToString().substr(0,20).c_str(), - DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(), + pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", block.GetBlockTime()).c_str(), block.vtx.size()); PrintWallets(block); - // put the main timechain first + // put the main time-chain first vector& vNext = mapNext[pindex]; for (unsigned int i = 0; i < vNext.size(); i++) { @@ -2194,61 +3046,75 @@ void PrintBlockTree() } } -bool LoadExternalBlockFile(FILE* fileIn) +bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) { + int64 nStart = GetTimeMillis(); + int nLoaded = 0; - { - LOCK(cs_main); - try { - CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION); - unsigned int nPos = 0; - while (nPos != (unsigned int)-1 && blkdat.good() && !fRequestShutdown) - { - unsigned char pchData[65536]; - do { - fseek(blkdat, nPos, SEEK_SET); - int nRead = fread(pchData, 1, sizeof(pchData), blkdat); - if (nRead <= 8) - { - nPos = (unsigned int)-1; - break; - } - void* nFind = memchr(pchData, pchMessageStart[0], nRead+1-sizeof(pchMessageStart)); - if (nFind) - { - if (memcmp(nFind, pchMessageStart, sizeof(pchMessageStart))==0) - { - nPos += ((unsigned char*)nFind - pchData) + sizeof(pchMessageStart); - break; - } - nPos += ((unsigned char*)nFind - pchData) + 1; - } - else - nPos += sizeof(pchData) - sizeof(pchMessageStart) + 1; - } while(!fRequestShutdown); - if (nPos == (unsigned int)-1) - break; - fseek(blkdat, nPos, SEEK_SET); - unsigned int nSize; - blkdat >> nSize; - if (nSize > 0 && nSize <= MAX_BLOCK_SIZE) - { - CBlock block; - blkdat >> block; - if (ProcessBlock(NULL,&block)) - { - nLoaded++; - nPos += 4 + nSize; - } - } + try { + CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + uint64 nStartByte = 0; + if (dbp) { + // (try to) skip already indexed part + CBlockFileInfo info; + if (pblocktree->ReadBlockFileInfo(dbp->nFile, info)) { + nStartByte = info.nSize; + blkdat.Seek(info.nSize); } } - catch (std::exception &e) { - printf("%s() : Deserialize or I/O error caught during load\n", - __PRETTY_FUNCTION__); + uint64 nRewind = blkdat.GetPos(); + while (blkdat.good() && !blkdat.eof()) { + boost::this_thread::interruption_point(); + + blkdat.SetPos(nRewind); + nRewind++; // start one byte further next time, in case of failure + blkdat.SetLimit(); // remove former limit + unsigned int nSize = 0; + try { + // locate a header + unsigned char buf[4]; + blkdat.FindByte(pchMessageStart[0]); + nRewind = blkdat.GetPos()+1; + blkdat >> FLATDATA(buf); + if (memcmp(buf, pchMessageStart, 4)) + continue; + // read size + blkdat >> nSize; + if (nSize < 80 || nSize > MAX_BLOCK_SIZE) + continue; + } catch (std::exception &e) { + // no valid block header found; don't complain + break; + } + try { + // read block + uint64 nBlockPos = blkdat.GetPos(); + blkdat.SetLimit(nBlockPos + nSize); + CBlock block; + blkdat >> block; + nRewind = blkdat.GetPos(); + + // process block + if (nBlockPos >= nStartByte) { + LOCK(cs_main); + if (dbp) + dbp->nPos = nBlockPos; + CValidationState state; + if (ProcessBlock(state, NULL, &block, dbp)) + nLoaded++; + if (state.IsError()) + break; + } + } catch (std::exception &e) { + printf("%s() : Deserialize or I/O error caught during load\n", __PRETTY_FUNCTION__); + } } + fclose(fileIn); + } catch(std::runtime_error &e) { + AbortNode(_("Error: system error: ") + e.what()); } - printf("Loaded %i blocks from external file\n", nLoaded); + if (nLoaded > 0) + printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart); return nLoaded > 0; } @@ -2260,22 +3126,27 @@ bool LoadExternalBlockFile(FILE* fileIn) + ////////////////////////////////////////////////////////////////////////////// // // CAlert // -map mapAlerts; -CCriticalSection cs_mapAlerts; +extern map mapAlerts; +extern CCriticalSection cs_mapAlerts; string GetWarnings(string strFor) { int nPriority = 0; string strStatusBar; string strRPC; + if (GetBoolArg("-testsafemode")) strRPC = "test"; + 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"); + // Misc warnings like out of disk space and clock is wrong if (strMiscWarning != "") { @@ -2284,10 +3155,10 @@ string GetWarnings(string strFor) } // Longer invalid proof-of-work chain - if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6) + if (pindexBest && nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256()) { nPriority = 2000; - strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade."; + strStatusBar = strRPC = _("Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade."); } // Alerts @@ -2312,69 +3183,6 @@ string GetWarnings(string strFor) return "error"; } -CAlert CAlert::getAlertByHash(const uint256 &hash) -{ - CAlert retval; - { - LOCK(cs_mapAlerts); - map::iterator mi = mapAlerts.find(hash); - if(mi != mapAlerts.end()) - retval = mi->second; - } - return retval; -} - -bool CAlert::ProcessAlert() -{ - if (!CheckSignature()) - return false; - if (!IsInEffect()) - return false; - - { - LOCK(cs_mapAlerts); - // Cancel previous alerts - for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) - { - const CAlert& alert = (*mi).second; - if (Cancels(alert)) - { - printf("cancelling alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); - mapAlerts.erase(mi++); - } - else if (!alert.IsInEffect()) - { - printf("expiring alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); - mapAlerts.erase(mi++); - } - else - mi++; - } - - // Check if this alert has been cancelled - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.Cancels(*this)) - { - printf("alert already cancelled by %d\n", alert.nID); - return false; - } - } - - // Add to mapAlerts - mapAlerts.insert(make_pair(GetHash(), *this)); - // Notify UI if it applies to me - if(AppliesToMe()) - uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); - } - - printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); - return true; -} - @@ -2388,22 +3196,20 @@ bool CAlert::ProcessAlert() // -bool static AlreadyHave(CTxDB& txdb, const CInv& inv) +bool static AlreadyHave(const CInv& inv) { switch (inv.type) { case MSG_TX: { - bool txInMap = false; + bool txInMap = false; { - LOCK(mempool.cs); - txInMap = (mempool.exists(inv.hash)); + LOCK(mempool.cs); + txInMap = mempool.exists(inv.hash); } - return txInMap || - mapOrphanTransactions.count(inv.hash) || - txdb.ContainsTx(inv.hash); + return txInMap || mapOrphanTransactions.count(inv.hash) || + pcoinsTip->HaveCoins(inv.hash); } - case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash); @@ -2416,17 +3222,151 @@ bool static AlreadyHave(CTxDB& txdb, const CInv& inv) // The message start string is designed to be unlikely to occur in normal data. -// The characters are rarely used upper ascii, not valid as UTF-8, and produce +// The characters are rarely used upper ASCII, not valid as UTF-8, and produce // a large 4-byte int at any alignment. -unsigned char pchMessageStart[4] = { 0xfa, 0xc3, 0xb6, 0xda }; +unsigned char pchMessageStart[4] = { 0xfa, 0xc3, 0xb6, 0xda }; // CasinoCoin +void static ProcessGetData(CNode* pfrom) +{ + std::deque::iterator it = pfrom->vRecvGetData.begin(); + + vector vNotFound; + + while (it != pfrom->vRecvGetData.end()) { + // Don't bother if send buffer is too full to respond anyway + if (pfrom->nSendSize >= SendBufferSize()) + break; + + // Don't waste work on slow peers until they catch up on the blocks we + // give them. 80 bytes is just the size of a block header - obviously + // the minimum we might return. + if (pfrom->nBlocksRequested * 80 > pfrom->nSendBytes) + break; + + const CInv &inv = *it; + { + boost::this_thread::interruption_point(); + it++; + + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) + { + bool send = true; + map::iterator mi = mapBlockIndex.find(inv.hash); + pfrom->nBlocksRequested++; + if (mi != mapBlockIndex.end()) + { + // If the requested block is at a height below our last + // checkpoint, only serve it if it's in the checkpointed chain + int nHeight = ((*mi).second)->nHeight; + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); + if (pcheckpoint && nHeight < pcheckpoint->nHeight) { + if (!((*mi).second)->IsInMainChain()) + { + printf("ProcessGetData(): ignoring request for old block that isn't in the main chain\n"); + send = false; + } + } + } else { + send = false; + } + if (send) + { + // Send block from disk + CBlock block; + block.ReadFromDisk((*mi).second); + if (inv.type == MSG_BLOCK) + pfrom->PushMessage("block", block); + else // MSG_FILTERED_BLOCK) + { + LOCK(pfrom->cs_filter); + if (pfrom->pfilter) + { + CMerkleBlock merkleBlock(block, *pfrom->pfilter); + pfrom->PushMessage("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 didnt 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 PairType; + BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) + if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second))) + pfrom->PushMessage("tx", block.vtx[pair.first]); + } + // else + // no response + } + + // Trigger them 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 vInv; + vInv.push_back(CInv(MSG_BLOCK, hashBestChain)); + pfrom->PushMessage("inv", vInv); + pfrom->hashContinue = 0; + } + } + } + else if (inv.IsKnownType()) + { + // Send stream from relay memory + bool pushed = false; + { + LOCK(cs_mapRelay); + map::iterator mi = mapRelay.find(inv); + if (mi != mapRelay.end()) { + pfrom->PushMessage(inv.GetCommand(), (*mi).second); + pushed = true; + } + } + if (!pushed && inv.type == MSG_TX) { + LOCK(mempool.cs); + if (mempool.exists(inv.hash)) { + CTransaction tx = mempool.lookup(inv.hash); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << tx; + pfrom->PushMessage("tx", ss); + pushed = true; + } + } + if (!pushed) { + vNotFound.push_back(inv); + } + } + + // Track requests for our stuff. + Inventory(inv.hash); + + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_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("notfound", vNotFound); + } +} + bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { - static map mapReuseKey; RandAddSeedPerfmon(); if (fDebug) - printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size()); + printf("received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size()); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { printf("dropmessagestest DROPPING RECV MESSAGE\n"); @@ -2451,10 +3391,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CAddress addrFrom; uint64 nNonce = 1; vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; - if (pfrom->nVersion < MIN_PROTO_VERSION) + if (pfrom->nVersion < MIN_PEER_PROTO_VERSION) { - // Since February 20, 2012, the protocol is initiated at version 209, - // and earlier versions are no longer supported + // disconnect from peers older than this proto version printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion); pfrom->fDisconnect = true; return false; @@ -2464,10 +3403,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->nVersion = 300; if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; - if (!vRecv.empty()) + if (!vRecv.empty()) { vRecv >> pfrom->strSubVer; + pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); + } if (!vRecv.empty()) vRecv >> pfrom->nStartingHeight; + if (!vRecv.empty()) + vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message + else + pfrom->fRelayTxes = true; if (pfrom->fInbound && addrMe.IsRoutable()) { @@ -2493,7 +3438,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Change version pfrom->PushMessage("verack"); - pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); if (!pfrom->fInbound) { @@ -2520,17 +3465,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } } - // Ask the first connected node for block updates - static int nAskedForBlocks = 0; - if (!pfrom->fClient && !pfrom->fOneShot && - (pfrom->nVersion < NOBLKS_VERSION_START || - pfrom->nVersion >= NOBLKS_VERSION_END) && - (nAskedForBlocks < 1 || vNodes.size() <= 1)) - { - nAskedForBlocks++; - pfrom->PushGetBlocks(pindexBest, uint256(0)); - } - // Relay alerts { LOCK(cs_mapAlerts); @@ -2540,7 +3474,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->fSuccessfullyConnected = true; - printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); + printf("receive version message: %s: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->cleanSubVer.c_str(), pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); cPeerBlockCounts.input(pfrom->nStartingHeight); } @@ -2556,7 +3490,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (strCommand == "verack") { - pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); } @@ -2571,7 +3505,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vAddr.size() > 1000) { pfrom->Misbehaving(20); - return error("message addr size() = %d", vAddr.size()); + return error("message addr size() = %"PRIszu"", vAddr.size()); } // Store the new addresses @@ -2580,8 +3514,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) int64 nSince = nNow - 10 * 60; BOOST_FOREACH(CAddress& addr, vAddr) { - if (fShutdown) - return true; + boost::this_thread::interruption_point(); + if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) addr.nTime = nNow - 5 * 24 * 60 * 60; pfrom->AddAddressKnown(addr); @@ -2631,10 +3565,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { vector vInv; vRecv >> vInv; - if (vInv.size() > 50000) + if (vInv.size() > MAX_INV_SZ) { pfrom->Misbehaving(20); - return error("message inv size() = %d", vInv.size()); + return error("message inv size() = %"PRIszu"", vInv.size()); } // find last block in inv vector @@ -2645,28 +3579,26 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) break; } } - CTxDB txdb("r"); for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { const CInv &inv = vInv[nInv]; - if (fShutdown) - return true; + boost::this_thread::interruption_point(); pfrom->AddInventoryKnown(inv); - bool fAlreadyHave = AlreadyHave(txdb, inv); + bool fAlreadyHave = AlreadyHave(inv); if (fDebug) printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new"); - if (!fAlreadyHave) - pfrom->AskFor(inv); - else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { + if (!fAlreadyHave) { + if (!fImporting && !fReindex) + pfrom->AskFor(inv); + } else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); } else if (nInv == nLastBlock) { // In case we are on a very long side-chain, it is possible that we already have // the last block in an inv bundle sent in response to getblocks. Try to detect // this situation and push another getblocks to continue. - std::vector vGetData(1,inv); pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0)); if (fDebug) printf("force request: %s\n", inv.ToString().c_str()); @@ -2682,59 +3614,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { vector vInv; vRecv >> vInv; - if (vInv.size() > 50000) + if (vInv.size() > MAX_INV_SZ) { pfrom->Misbehaving(20); - return error("message getdata size() = %d", vInv.size()); + return error("message getdata size() = %"PRIszu"", vInv.size()); } if (fDebugNet || (vInv.size() != 1)) - printf("received getdata (%d invsz)\n", vInv.size()); + printf("received getdata (%"PRIszu" invsz)\n", vInv.size()); - BOOST_FOREACH(const CInv& inv, vInv) - { - if (fShutdown) - return true; - if (fDebugNet || (vInv.size() == 1)) - printf("received getdata for: %s\n", inv.ToString().c_str()); + if ((fDebugNet && vInv.size() > 0) || (vInv.size() == 1)) + printf("received getdata for: %s\n", vInv[0].ToString().c_str()); - if (inv.type == MSG_BLOCK) - { - // Send block from disk - map::iterator mi = mapBlockIndex.find(inv.hash); - if (mi != mapBlockIndex.end()) - { - CBlock block; - block.ReadFromDisk((*mi).second); - pfrom->PushMessage("block", block); - - // Trigger them 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 vInv; - vInv.push_back(CInv(MSG_BLOCK, hashBestChain)); - pfrom->PushMessage("inv", vInv); - pfrom->hashContinue = 0; - } - } - } - else if (inv.IsKnownType()) - { - // Send stream from relay memory - { - LOCK(cs_mapRelay); - map::iterator mi = mapRelay.find(inv); - if (mi != mapRelay.end()) - pfrom->PushMessage(inv.GetCommand(), (*mi).second); - } - } - - // Track requests for our stuff - Inventory(inv.hash); - } + pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); + ProcessGetData(pfrom); } @@ -2751,12 +3644,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (pindex) pindex = pindex->pnext; int nLimit = 500; - printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit); + printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit); for (; pindex; pindex = pindex->pnext) { if (pindex->GetBlockHash() == hashStop) { - printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str()); + printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); break; } pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); @@ -2764,7 +3657,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { // When this block is requested, we'll send an inv that'll make them // getblocks the next batch of inventory. - printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str()); + printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pfrom->hashContinue = pindex->GetBlockHash(); break; } @@ -2795,9 +3688,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pindex = pindex->pnext; } + // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end vector vHeaders; int nLimit = 2000; - printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str()); + printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str()); for (; pindex; pindex = pindex->pnext) { vHeaders.push_back(pindex->GetBlockHeader()); @@ -2813,60 +3707,55 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vector vWorkQueue; vector vEraseQueue; CDataStream vMsg(vRecv); - CTxDB txdb("r"); CTransaction tx; vRecv >> tx; CInv inv(MSG_TX, tx.GetHash()); pfrom->AddInventoryKnown(inv); - // Truncate messages to the size of the tx in them - unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - unsigned int oldSize = vMsg.size(); - if (nSize < oldSize) { - vMsg.resize(nSize); - printf("truncating oversized TX %s (%u -> %u)\n", - tx.GetHash().ToString().c_str(), - oldSize, nSize); - } - bool fMissingInputs = false; - if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs)) + CValidationState state; + if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs)) { - SyncWithWallets(tx, NULL, true); - RelayMessage(inv, vMsg); + RelayTransaction(tx, inv.hash); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); vEraseQueue.push_back(inv.hash); + printf("AcceptToMemoryPool: %s %s : accepted %s (poolsz %"PRIszu")\n", + pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), + tx.GetHash().ToString().c_str(), + mempool.mapTx.size()); + // Recursively process any orphan transactions that depended on this one for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hashPrev = vWorkQueue[i]; - for (map::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin(); + for (set::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin(); mi != mapOrphanTransactionsByPrev[hashPrev].end(); ++mi) { - const CDataStream& vMsg = *((*mi).second); - CTransaction tx; - CDataStream(vMsg) >> tx; - CInv inv(MSG_TX, tx.GetHash()); + const uint256& orphanHash = *mi; + const CTransaction& orphanTx = mapOrphanTransactions[orphanHash]; 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 (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2)) + if (tx.AcceptToMemoryPool(stateDummy, true, true, &fMissingInputs2)) { - printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); - SyncWithWallets(tx, NULL, true); - RelayMessage(inv, vMsg); - mapAlreadyAskedFor.erase(inv); - vWorkQueue.push_back(inv.hash); - vEraseQueue.push_back(inv.hash); + printf(" accepted orphan tx %s\n", orphanHash.ToString().c_str()); + RelayTransaction(orphanTx, orphanHash); + mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash)); + vWorkQueue.push_back(orphanHash); + vEraseQueue.push_back(orphanHash); } else if (!fMissingInputs2) { - // invalid orphan - vEraseQueue.push_back(inv.hash); - printf(" removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); + // invalid or too-little-fee orphan + vEraseQueue.push_back(orphanHash); + printf(" removed orphan tx %s\n", orphanHash.ToString().c_str()); } } } @@ -2876,31 +3765,42 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } else if (fMissingInputs) { - AddOrphanTx(vMsg); + AddOrphanTx(tx); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS); if (nEvicted > 0) printf("mapOrphan overflow, removed %u tx\n", nEvicted); } - if (tx.nDoS) pfrom->Misbehaving(tx.nDoS); + int nDoS = 0; + if (state.IsInvalid(nDoS)) + { + printf("%s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(), + pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str()); + if (nDoS > 0) + pfrom->Misbehaving(nDoS); + } } - else if (strCommand == "block") + else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing { CBlock block; vRecv >> block; - printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str()); + printf("received block %s\n", block.GetHash().ToString().c_str()); // block.print(); CInv inv(MSG_BLOCK, block.GetHash()); pfrom->AddInventoryKnown(inv); - if (ProcessBlock(pfrom, &block)) + CValidationState state; + if (ProcessBlock(state, pfrom, &block) || state.CorruptionPossible()) mapAlreadyAskedFor.erase(inv); - if (block.nDoS) pfrom->Misbehaving(block.nDoS); + int nDoS = 0; + if (state.IsInvalid(nDoS)) + if (nDoS > 0) + pfrom->Misbehaving(nDoS); } @@ -2913,50 +3813,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } - else if (strCommand == "checkorder") + else if (strCommand == "mempool") { - uint256 hashReply; - vRecv >> hashReply; - - if (!GetBoolArg("-allowreceivebyip")) - { - pfrom->PushMessage("reply", hashReply, (int)2, string("")); - return true; + std::vector vtxid; + LOCK2(mempool.cs, pfrom->cs_filter); + mempool.queryHashes(vtxid); + vector vInv; + BOOST_FOREACH(uint256& hash, vtxid) { + CInv inv(MSG_TX, hash); + if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(mempool.lookup(hash), hash)) || + (!pfrom->pfilter)) + vInv.push_back(inv); + if (vInv.size() == MAX_INV_SZ) + break; } - - CWalletTx order; - vRecv >> order; - - /// we have a chance to check the order here - - // Keep giving the same key to the same ip until they use it - if (!mapReuseKey.count(pfrom->addr)) - pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true); - - // Send back approval of order and pubkey to use - CScript scriptPubKey; - scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG; - pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey); - } - - - else if (strCommand == "reply") - { - uint256 hashReply; - vRecv >> hashReply; - - CRequestTracker tracker; - { - LOCK(pfrom->cs_mapRequests); - map::iterator mi = pfrom->mapRequests.find(hashReply); - if (mi != pfrom->mapRequests.end()) - { - tracker = (*mi).second; - pfrom->mapRequests.erase(mi); - } - } - if (!tracker.IsNull()) - tracker.fn(tracker.param1, vRecv); + if (vInv.size() > 0) + pfrom->PushMessage("inv", vInv); } @@ -2987,19 +3859,90 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CAlert alert; vRecv >> alert; - if (alert.ProcessAlert()) + uint256 alertHash = alert.GetHash(); + if (pfrom->setKnown.count(alertHash) == 0) { - // Relay - pfrom->setKnown.insert(alert.GetHash()); + if (alert.ProcessAlert()) { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - alert.RelayTo(pnode); + // Relay + pfrom->setKnown.insert(alertHash); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + alert.RelayTo(pnode); + } + } + else { + // Small DoS penalty so peers that send us lots of + // duplicate/expired/invalid-signature/whatever alerts + // eventually get banned. + // This isn't a Misbehaving(100) (immediate ban) because the + // peer might be an older or different implementation with + // a different signature key, etc. + pfrom->Misbehaving(10); } } } + else if (!fBloomFilters && + (strCommand == "filterload" || + strCommand == "filteradd" || + strCommand == "filterclear")) + { + pfrom->CloseSocketDisconnect(); + return error("peer %s attempted to set a bloom filter even though we do not advertise that service", + pfrom->addr.ToString().c_str()); + } + + else if (strCommand == "filterload") + { + CBloomFilter filter; + vRecv >> filter; + + if (!filter.IsWithinSizeConstraints()) + // There is no excuse for sending a too-large filter + pfrom->Misbehaving(100); + else + { + LOCK(pfrom->cs_filter); + delete pfrom->pfilter; + pfrom->pfilter = new CBloomFilter(filter); + pfrom->pfilter->UpdateEmptyFull(); + } + pfrom->fRelayTxes = true; + } + + + else if (strCommand == "filteradd") + { + vector 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) + { + pfrom->Misbehaving(100); + } else { + LOCK(pfrom->cs_filter); + if (pfrom->pfilter) + pfrom->pfilter->insert(vData); + else + pfrom->Misbehaving(100); + } + } + + + else if (strCommand == "filterclear") + { + LOCK(pfrom->cs_filter); + delete pfrom->pfilter; + pfrom->pfilter = new CBloomFilter(); + pfrom->fRelayTxes = true; + } + + else { // Ignore unknown commands for extensibility @@ -3015,13 +3958,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) return true; } +// requires LOCK(cs_vRecvMsg) bool ProcessMessages(CNode* pfrom) { - CDataStream& vRecv = pfrom->vRecv; - if (vRecv.empty()) - return true; //if (fDebug) - // printf("ProcessMessages(%u bytes)\n", vRecv.size()); + // printf("ProcessMessages(%zu messages)\n", pfrom->vRecvMsg.size()); // // Message format @@ -3031,33 +3972,44 @@ bool ProcessMessages(CNode* pfrom) // (4) checksum // (x) data // + bool fOk = true; - loop - { + if (!pfrom->vRecvGetData.empty()) + ProcessGetData(pfrom); + + // this maintains the order of responses + if (!pfrom->vRecvGetData.empty()) return fOk; + + std::deque::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->vSend.size() >= SendBufferSize()) + if (pfrom->nSendSize >= SendBufferSize()) break; + // get next message + CNetMessage& msg = *it; + + //if (fDebug) + // printf("ProcessMessages(message %u msgsz, %zu bytes, complete:%s)\n", + // 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 - CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); - int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); - if (vRecv.end() - pstart < nHeaderSize) - { - if ((int)vRecv.size() > nHeaderSize) - { - printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n"); - vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); - } + if (memcmp(msg.hdr.pchMessageStart, pchMessageStart, sizeof(pchMessageStart)) != 0) { + printf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n"); + fOk = false; break; } - if (pstart - vRecv.begin() > 0) - printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin()); - vRecv.erase(vRecv.begin(), pstart); // Read header - vector vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); - CMessageHeader hdr; - vRecv >> hdr; + CMessageHeader& hdr = msg.hdr; if (!hdr.IsValid()) { printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str()); @@ -3067,19 +4019,9 @@ bool ProcessMessages(CNode* pfrom) // Message size unsigned int nMessageSize = hdr.nMessageSize; - if (nMessageSize > MAX_SIZE) - { - printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize); - continue; - } - if (nMessageSize > vRecv.size()) - { - // Rewind and wait for rest of message - vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); - break; - } // Checksum + CDataStream& vRecv = msg.vRecv; uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); @@ -3090,31 +4032,26 @@ bool ProcessMessages(CNode* pfrom) continue; } - // Copy message to its own buffer - CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); - vRecv.ignore(nMessageSize); - // Process message bool fRet = false; try { { LOCK(cs_main); - fRet = ProcessMessage(pfrom, strCommand, vMsg); + fRet = ProcessMessage(pfrom, strCommand, vRecv); } - if (fShutdown) - return true; + boost::this_thread::interruption_point(); } catch (std::ios_base::failure& e) { if (strstr(e.what(), "end of data")) { - // Allow exceptions from underlength message on vRecv + // Allow exceptions from under-length message on vRecv printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what()); } else if (strstr(e.what(), "size too large")) { - // Allow exceptions from overlong size + // Allow exceptions from over-long size printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what()); } else @@ -3122,6 +4059,9 @@ bool ProcessMessages(CNode* pfrom) PrintExceptionContinue(&e, "ProcessMessages()"); } } + catch (boost::thread_interrupted) { + throw; + } catch (std::exception& e) { PrintExceptionContinue(&e, "ProcessMessages()"); } catch (...) { @@ -3130,10 +4070,15 @@ bool ProcessMessages(CNode* pfrom) if (!fRet) printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize); + + break; } - vRecv.Compact(); - return true; + // In case the connection got shut down, its receive buffer was wiped + if (!pfrom->fDisconnect) + pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it); + + return fOk; } @@ -3147,7 +4092,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Keep-alive ping. We send a nonce of zero because we don't use it anywhere // right now. - if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { + if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) { uint64 nonce = 0; if (pto->nVersion > BIP0031_VERSION) pto->PushMessage("ping", nonce); @@ -3155,8 +4100,19 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->PushMessage("ping"); } + // Start block sync + if (pto->fStartSync && !fImporting && !fReindex) { + pto->fStartSync = false; + pto->PushGetBlocks(pindexBest, uint256(0)); + } + // Resend wallet transactions that haven't gotten in a block yet - ResendWalletTransactions(); + // Except during reindex, importing and IBD, when old wallet + // transactions become unconfirmed and spams other nodes. + if (!fReindex && !fImporting && !IsInitialBlockDownload()) + { + ResendWalletTransactions(); + } // Address refresh broadcast static int64 nLastRebroadcast; @@ -3272,11 +4228,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // vector vGetData; int64 nNow = GetTime() * 1000000; - CTxDB txdb("r"); while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) { const CInv& inv = (*pto->mapAskFor.begin()).second; - if (!AlreadyHave(txdb, inv)) + if (!AlreadyHave(inv)) { if (fDebugNet) printf("sending getdata: %s\n", inv.ToString().c_str()); @@ -3286,7 +4241,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->PushMessage("getdata", vGetData); vGetData.clear(); } - mapAlreadyAskedFor[inv] = nNow; } pto->mapAskFor.erase(pto->mapAskFor.begin()); } @@ -3312,7 +4266,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) ////////////////////////////////////////////////////////////////////////////// // -// BitcoinMiner +// CasinoCoinMiner // int static FormatHashBlocks(void* pbuffer, unsigned int len) @@ -3351,39 +4305,6 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit) ((uint32_t*)pstate)[i] = ctx.h[i]; } -// -// ScanHash scans nonces looking for a hash with at least some zero bits. -// It operates on big endian data. Caller does the byte reversing. -// All input buffers are 16-byte aligned. nNonce is usually preserved -// between calls, but periodically or if nNonce is 0xffff0000 or above, -// the block is rebuilt and nNonce starts over at zero. -// -unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) -{ - unsigned int& nNonce = *(unsigned int*)(pdata + 12); - for (;;) - { - // Crypto++ SHA-256 - // Hash pdata using pmidstate as the starting state into - // preformatted buffer phash1, then hash phash1 into phash - nNonce++; - SHA256Transform(phash1, pdata, pmidstate); - SHA256Transform(phash, phash1, pSHA256InitState); - - // Return the nonce if the hash has at least some zero bits, - // caller will check if it has enough to reach the target - if (((unsigned short*)phash)[14] == 0) - return nNonce; - - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xffff) == 0) - { - nHashesDone = 0xffff+1; - return (unsigned int) -1; - } - } -} - // Some explaining would be appreciated class COrphan { @@ -3391,18 +4312,20 @@ public: CTransaction* ptx; set setDependsOn; double dPriority; + double dFeePerKb; COrphan(CTransaction* ptxIn) { ptx = ptxIn; - dPriority = 0; + dPriority = dFeePerKb = 0; } void print() const { - printf("COrphan(hash=%s, dPriority=%.1f)\n", ptx->GetHash().ToString().substr(0,10).c_str(), dPriority); + printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", + ptx->GetHash().ToString().c_str(), dPriority, dFeePerKb); BOOST_FOREACH(uint256 hash, setDependsOn) - printf(" setDependsOn %s\n", hash.ToString().substr(0,10).c_str()); + printf(" setDependsOn %s\n", hash.ToString().c_str()); } }; @@ -3410,35 +4333,80 @@ public: uint64 nLastBlockTx = 0; uint64 nLastBlockSize = 0; -CBlock* CreateNewBlock(CReserveKey& reservekey) +// We want to sort transactions by priority and fee, so: +typedef boost::tuple TxPriority; +class TxPriorityCompare { - CBlockIndex* pindexPrev = pindexBest; + bool byFee; +public: + TxPriorityCompare(bool _byFee) : byFee(_byFee) { } + bool operator()(const TxPriority& a, const TxPriority& b) + { + if (byFee) + { + if (a.get<1>() == b.get<1>()) + return a.get<0>() < b.get<0>(); + return a.get<1>() < b.get<1>(); + } + else + { + if (a.get<0>() == b.get<0>()) + return a.get<1>() < b.get<1>(); + return a.get<0>() < b.get<0>(); + } + } +}; +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) +{ // Create new block - auto_ptr pblock(new CBlock()); - if (!pblock.get()) + auto_ptr pblocktemplate(new CBlockTemplate()); + if(!pblocktemplate.get()) return NULL; + CBlock *pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx CTransaction txNew; txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vout.resize(1); - txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; + txNew.vout[0].scriptPubKey = scriptPubKeyIn; // Add our coinbase tx as first transaction pblock->vtx.push_back(txNew); + pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxSigOps.push_back(-1); // updated at end + + // Largest block you're willing to create: + unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); + // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + + // 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); + + // Minimum block size you want to create; block will be filled with free transactions + // until there are no more or the block reaches this size: + unsigned int nBlockMinSize = GetArg("-blockminsize", 0); + nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); // Collect memory pool transactions into the block int64 nFees = 0; { LOCK2(cs_main, mempool.cs); - CTxDB txdb("r"); + CBlockIndex* pindexPrev = pindexBest; + CCoinsViewCache view(*pcoinsTip, true); // Priority order to process transactions list vOrphan; // list memory doesn't move map > mapDependers; - multimap mapPriority; + bool fPrintPriority = GetBoolArg("-printpriority"); + + // This vector will be sorted into a priority queue: + vector vecPriority; + vecPriority.reserve(mempool.mapTx.size()); for (map::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { CTransaction& tx = (*mi).second; @@ -3447,13 +4415,26 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) COrphan* porphan = NULL; double dPriority = 0; + int64 nTotalIn = 0; + bool fMissingInputs = false; BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Read prev transaction - CTransaction txPrev; - CTxIndex txindex; - if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + if (!view.HaveCoins(txin.prevout.hash)) { + // This should never happen; all transactions in the memory + // pool should connect to either transactions in the chain + // or other transactions in the memory pool. + if (!mempool.mapTx.count(txin.prevout.hash)) + { + printf("ERROR: mempool transaction missing input\n"); + if (fDebug) assert("mempool transaction missing input" == 0); + fMissingInputs = true; + if (porphan) + vOrphan.pop_back(); + break; + } + // Has to wait for dependencies if (!porphan) { @@ -3463,51 +4444,60 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) } mapDependers[txin.prevout.hash].push_back(porphan); porphan->setDependsOn.insert(txin.prevout.hash); + nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue; continue; } - int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + const CCoins &coins = view.GetCoins(txin.prevout.hash); - // Read block header - int nConf = txindex.GetDepthInMainChain(); + int64 nValueIn = coins.vout[txin.prevout.n].nValue; + nTotalIn += nValueIn; + + int nConf = pindexPrev->nHeight - coins.nHeight + 1; dPriority += (double)nValueIn * nConf; - - if (fDebug && GetBoolArg("-printpriority")) - printf("priority nValueIn=%-12"PRI64d" nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority); } + if (fMissingInputs) continue; // Priority is sum(valuein * age) / txsize - dPriority /= ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + dPriority /= nTxSize; + + // This is a more accurate fee-per-kilobyte than is used by the client code, because the + // client code rounds up the size to the nearest 1K. That's good, because it gives an + // incentive to create smaller transactions. + double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0); if (porphan) - porphan->dPriority = dPriority; - else - mapPriority.insert(make_pair(-dPriority, &(*mi).second)); - - if (fDebug && GetBoolArg("-printpriority")) { - printf("priority %-20.1f %s\n%s", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str()); - if (porphan) - porphan->print(); - printf("\n"); + porphan->dPriority = dPriority; + porphan->dFeePerKb = dFeePerKb; } + else + vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second)); } // Collect transactions into block - map mapTestPool; uint64 nBlockSize = 1000; uint64 nBlockTx = 0; int nBlockSigOps = 100; - while (!mapPriority.empty()) + bool fSortedByFee = (nBlockPrioritySize <= 0); + + TxPriorityCompare comparer(fSortedByFee); + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + + while (!vecPriority.empty()) { - // Take highest priority transaction off priority queue - double dPriority = -(*mapPriority.begin()).first; - CTransaction& tx = *(*mapPriority.begin()).second; - mapPriority.erase(mapPriority.begin()); + // Take highest priority transaction off the priority queue: + double dPriority = vecPriority.front().get<0>(); + double dFeePerKb = vecPriority.front().get<1>(); + CTransaction& tx = *(vecPriority.front().get<2>()); + + std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); + vecPriority.pop_back(); // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN) + if (nBlockSize + nTxSize >= nBlockMaxSize) continue; // Legacy limits on sigOps: @@ -3515,41 +4505,53 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; - // Transaction fee required depends on block size - // CasinoCoind: Reduce the exempted free transactions to 500 bytes (from Bitcoin's 3000 bytes) - bool fAllowFree = (nBlockSize + nTxSize < 1500 || CTransaction::AllowFree(dPriority)); - int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK); - - // Connecting shouldn't fail due to dependency on other memory pool transactions - // because we're already processing them in order of dependency - map mapTestPoolTmp(mapTestPool); - MapPrevTx mapInputs; - bool fInvalid; - if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid)) + // Skip free transactions if we're past the minimum block size: + if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; - int64 nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); - if (nTxFees < nMinFee) + // Prioritize by fee once past the priority size or we run out of high-priority + // transactions: + if (!fSortedByFee && + ((nBlockSize + nTxSize >= nBlockPrioritySize) || (dPriority < COIN * 576 / 250))) + { + fSortedByFee = true; + comparer = TxPriorityCompare(fSortedByFee); + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + } + + if (!tx.HaveInputs(view)) continue; - nTxSigOps += tx.GetP2SHSigOpCount(mapInputs); + int64 nTxFees = tx.GetValueIn(view)-tx.GetValueOut(); + + nTxSigOps += tx.GetP2SHSigOpCount(view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; - if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true)) + CValidationState state; + if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH)) continue; - mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(1,1,1), tx.vout.size()); - swap(mapTestPool, mapTestPoolTmp); + + CTxUndo txundo; + uint256 hash = tx.GetHash(); + tx.UpdateCoins(state, view, txundo, pindexPrev->nHeight+1, hash); // Added pblock->vtx.push_back(tx); + pblocktemplate->vTxFees.push_back(nTxFees); + pblocktemplate->vTxSigOps.push_back(nTxSigOps); nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; nFees += nTxFees; + if (fPrintPriority) + { + printf("priority %.1f feeperkb %.1f txid %s\n", + dPriority, dFeePerKb, tx.GetHash().ToString().c_str()); + } + // Add transactions that depend on this one to the priority queue - uint256 hash = tx.GetHash(); if (mapDependers.count(hash)) { BOOST_FOREACH(COrphan* porphan, mapDependers[hash]) @@ -3558,7 +4560,10 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) { porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) - mapPriority.insert(make_pair(-porphan->dPriority, porphan->ptx)); + { + vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); + std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); + } } } } @@ -3566,21 +4571,40 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - printf("CreateNewBlock(): total size %lu\n", nBlockSize); + printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); + pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + pblocktemplate->vTxFees[0] = -nFees; + + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + pblock->UpdateTime(pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); + pblock->nNonce = 0; + pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0; + pblocktemplate->vTxSigOps[0] = pblock->vtx[0].GetLegacySigOpCount(); + + CBlockIndex indexDummy(*pblock); + indexDummy.pprev = pindexPrev; + indexDummy.nHeight = pindexPrev->nHeight + 1; + CCoinsViewCache viewNew(*pcoinsTip, true); + CValidationState state; + if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true)) + throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); } - pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); - // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - pblock->UpdateTime(pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get()); - pblock->nNonce = 0; - - return pblock.release(); + return pblocktemplate.release(); } +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) +{ + CPubKey pubkey; + if (!reservekey.GetReservedKey(pubkey)) + return NULL; + + CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG; + return CreateNewBlock(scriptPubKey); +} void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { @@ -3592,7 +4616,8 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& hashPrevBlock = pblock->hashPrevBlock; } ++nExtraNonce; - pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS; + unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 + pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS; assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); @@ -3602,7 +4627,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1) { // - // Prebuild hash buffers + // Pre-build hash buffers // struct { @@ -3654,7 +4679,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) return false; //// debug print - printf("BitcoinMiner:\n"); + printf("CasinoCoinMiner:\n"); printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); pblock->print(); printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); @@ -3663,7 +4688,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { LOCK(cs_main); if (pblock->hashPrevBlock != hashBestChain) - return error("BitcoinMiner : generated block is stale"); + return error("CasinoCoinMiner : generated block is stale"); // Remove key from key pool reservekey.KeepKey(); @@ -3675,44 +4700,27 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) } // Process this block the same as if we had received it from another node - if (!ProcessBlock(NULL, pblock)) - return error("BitcoinMiner : ProcessBlock, block not accepted"); + CValidationState state; + if (!ProcessBlock(state, NULL, pblock)) + return error("CasinoCoinMiner : ProcessBlock, block not accepted"); } return true; } -void static ThreadBitcoinMiner(void* parg); - -static bool fGenerateBitcoins = false; -static bool fLimitProcessors = false; -static int nLimitProcessors = -1; - -void static BitcoinMiner(CWallet *pwallet) +void static CasinoCoinMiner(CWallet *pwallet) { - printf("BitcoinMiner started\n"); + printf("CasinoCoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); - - // Make this thread recognisable as the mining thread - RenameThread("bitcoin-miner"); + RenameThread("casinocoin-miner"); // Each thread has its own key and counter CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; - while (fGenerateBitcoins) - { - if (fShutdown) - return; - while (vNodes.empty() || IsInitialBlockDownload()) - { - Sleep(1000); - if (fShutdown) - return; - if (!fGenerateBitcoins) - return; - } - + try { loop { + while (vNodes.empty()) + MilliSleep(1000); // // Create new block @@ -3720,22 +4728,23 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; CBlockIndex* pindexPrev = pindexBest; - auto_ptr pblock(CreateNewBlock(reservekey)); - if (!pblock.get()) + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + if (!pblocktemplate.get()) return; - IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce); - - printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size()); + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + printf("Running CasinoCoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); // - // Prebuild hash buffers + // Pre-build hash buffers // char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf); char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf); char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf); - FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1); + FormatHashBuffers(pblock, pmidstate, pdata, phash1); unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8); @@ -3750,7 +4759,6 @@ void static BitcoinMiner(CWallet *pwallet) loop { unsigned int nHashesDone = 0; - //unsigned int nNonceFound; uint256 thash; char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; @@ -3762,7 +4770,7 @@ void static BitcoinMiner(CWallet *pwallet) { // Found a solution SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock.get(), *pwalletMain, reservekey); + CheckWork(pblock, *pwallet, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); break; } @@ -3791,25 +4799,18 @@ void static BitcoinMiner(CWallet *pwallet) dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; - string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0); static int64 nLogTime; if (GetTime() - nLogTime > 30 * 60) { nLogTime = GetTime(); - printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); - printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0); + printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); } } } } // Check for stop or if block needs to be rebuilt - if (fShutdown) - return; - if (!fGenerateBitcoins) - return; - if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors) - return; + boost::this_thread::interruption_point(); if (vNodes.empty()) break; if (pblock->nNonce >= 0xffff0000) @@ -3829,55 +4830,110 @@ void static BitcoinMiner(CWallet *pwallet) hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); } } - } -} - -void static ThreadBitcoinMiner(void* parg) -{ - CWallet* pwallet = (CWallet*)parg; - try + } } + catch (boost::thread_interrupted) { - vnThreadsRunning[THREAD_MINER]++; - BitcoinMiner(pwallet); - vnThreadsRunning[THREAD_MINER]--; + printf("CasinoCoinMiner terminated\n"); + throw; } - catch (std::exception& e) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(&e, "ThreadBitcoinMiner()"); - } catch (...) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(NULL, "ThreadBitcoinMiner()"); - } - nHPSTimerStart = 0; - if (vnThreadsRunning[THREAD_MINER] == 0) - dHashesPerSec = 0; - printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]); } - void GenerateBitcoins(bool fGenerate, CWallet* pwallet) { - fGenerateBitcoins = fGenerate; - nLimitProcessors = GetArg("-genproclimit", -1); - if (nLimitProcessors == 0) - fGenerateBitcoins = false; - fLimitProcessors = (nLimitProcessors != -1); + static boost::thread_group* minerThreads = NULL; - if (fGenerate) + int nThreads = GetArg("-genproclimit", -1); + if (nThreads < 0) + nThreads = boost::thread::hardware_concurrency(); + + if (minerThreads != NULL) { - int nProcessors = boost::thread::hardware_concurrency(); - printf("%d processors\n", nProcessors); - if (nProcessors < 1) - nProcessors = 1; - if (fLimitProcessors && nProcessors > nLimitProcessors) - nProcessors = nLimitProcessors; - int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER]; - printf("Starting %d BitcoinMiner threads\n", nAddThreads); - for (int i = 0; i < nAddThreads; i++) - { - if (!CreateThread(ThreadBitcoinMiner, pwallet)) - printf("Error: CreateThread(ThreadBitcoinMiner) failed\n"); - Sleep(10); - } + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = NULL; + } + + if (nThreads == 0 || !fGenerate) + return; + + minerThreads = new boost::thread_group(); + for (int i = 0; i < nThreads; i++) + minerThreads->create_thread(boost::bind(&CasinoCoinMiner, pwallet)); +} + +// Amount compression: +// * If the amount is 0, output 0 +// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) +// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) +// * call the result n +// * output 1 + 10*(9*n + d - 1) + e +// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 +// (this is decodable, as d is in [1-9] and e is in [0-9]) + +uint64 CTxOutCompressor::CompressAmount(uint64 n) +{ + if (n == 0) + return 0; + int e = 0; + while (((n % 10) == 0) && e < 9) { + n /= 10; + e++; + } + if (e < 9) { + int d = (n % 10); + assert(d >= 1 && d <= 9); + n /= 10; + return 1 + (n*9 + d - 1)*10 + e; + } else { + return 1 + (n - 1)*10 + 9; } } + +uint64 CTxOutCompressor::DecompressAmount(uint64 x) +{ + // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 + if (x == 0) + return 0; + x--; + // x = 10*(9*n + d - 1) + e + int e = x % 10; + x /= 10; + uint64 n = 0; + if (e < 9) { + // x = 9*n + d - 1 + int d = (x % 9) + 1; + x /= 9; + // x = n + n = x*10 + d; + } else { + n = x+1; + } + while (e) { + n *= 10; + e--; + } + return n; +} + + +class CMainCleanup +{ +public: + CMainCleanup() {} + ~CMainCleanup() { + // block headers + std::map::iterator it1 = mapBlockIndex.begin(); + for (; it1 != mapBlockIndex.end(); it1++) + delete (*it1).second; + mapBlockIndex.clear(); + + // orphan blocks + std::map::iterator it2 = mapOrphanBlocks.begin(); + for (; it2 != mapOrphanBlocks.end(); it2++) + delete (*it2).second; + mapOrphanBlocks.clear(); + + // orphan transactions + mapOrphanTransactions.clear(); + } +} instance_of_cmaincleanup; diff --git a/src/main.h b/src/main.h index e6001f6..bd00c7a 100644 --- a/src/main.h +++ b/src/main.h @@ -1,17 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_MAIN_H #define BITCOIN_MAIN_H #include "bignum.h" +#include "sync.h" #include "net.h" -#include "key.h" #include "script.h" -#include "db.h" #include "scrypt.h" #include @@ -24,20 +21,47 @@ class CReserveKey; class CAddress; class CInv; -class CRequestTracker; class CNode; -static const unsigned int MAX_BLOCK_SIZE = 1000000; -static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; +struct CBlockIndexWorkComparator; + +/** The maximum allowed size for a serialized block, in bytes (network rule) */ +static const unsigned int MAX_BLOCK_SIZE = 1000000; // 1000KB block hard limit +/** Obsolete: maximum size for mined blocks */ +static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/4; // 250KB block soft limit +/** Default for -blockmaxsize, maximum size for mined blocks **/ +static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 250000; +/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ +static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 17000; +/** The maximum size for transactions we're willing to relay/mine */ +static const unsigned int MAX_STANDARD_TX_SIZE = 100000; +/** The maximum allowed number of signature check operations in a block (network rule) */ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; +/** The maximum number of orphan transactions kept in memory */ static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; -static const int64 MIN_TX_FEE = 2000000; -static const int64 MIN_RELAY_TX_FEE = MIN_TX_FEE; -static const int64 MAX_MONEY = 336000000 * COIN; // CasinoCoin: maximum of 336 million coins +/** The maximum number of entries in an 'inv' protocol message */ +static const unsigned int MAX_INV_SZ = 50000; +/** 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) */ +static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB +/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ +static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB +/** 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; +/** Dust Soft Limit, allowed with additional fee per output */ +static const int64 DUST_SOFT_LIMIT = 100000; // 0.001 CSC +/** Dust Hard Limit, ignored as wallet inputs (mininput default) */ +static const int64 DUST_HARD_LIMIT = 1000; // 0.00001 CSC mininput +/** No amount larger than this (in satoshi) is valid */ +static const int64 MAX_MONEY = 336000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } +/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 8; -// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. +/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */ static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC +/** Maximum number of script-checking threads allowed */ +static const int MAX_SCRIPTCHECK_THREADS = 16; #ifdef USE_UPNP static const int fHaveUPnP = true; #else @@ -54,11 +78,12 @@ extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern std::map mapBlockIndex; +extern std::set setBlockIndexValid; extern uint256 hashGenesisBlock; extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; -extern CBigNum bnBestChainWork; -extern CBigNum bnBestInvalidWork; +extern uint256 nBestChainWork; +extern uint256 nBestInvalidWork; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; extern unsigned int nTransactionsUpdated; @@ -71,6 +96,12 @@ extern int64 nTimeBestReceived; extern CCriticalSection cs_setpwalletRegistered; extern std::set setpwalletRegistered; extern unsigned char pchMessageStart[4]; +extern bool fImporting; +extern bool fReindex; +extern bool fBenchmark; +extern int nScriptCheckThreads; +extern bool fTxIndex; +extern unsigned int nCoinCacheSize; // Settings extern int64 nTransactionFee; @@ -81,32 +112,85 @@ static const uint64 nMinDiskSpace = 52428800; class CReserveKey; -class CTxDB; -class CTxIndex; +class CCoinsDB; +class CBlockTreeDB; +struct CDiskBlockPos; +class CCoins; +class CTxUndo; +class CCoinsView; +class CCoinsViewCache; +class CScriptCheck; +class CValidationState; +struct CBlockTemplate; + +/** Register a wallet to receive updates from core */ void RegisterWallet(CWallet* pwalletIn); +/** Unregister a wallet from core */ void UnregisterWallet(CWallet* pwalletIn); -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); -bool ProcessBlock(CNode* pfrom, CBlock* pblock); -bool CheckDiskSpace(uint64 nAdditionalBytes=0); -FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); -FILE* AppendBlockFile(unsigned int& nFileRet); -bool LoadBlockIndex(bool fAllowNew=true); +/** Push an updated transaction to all registered wallets */ +void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); +/** Process an incoming block */ +bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); +/** Check whether enough disk space is available for an incoming block */ +bool CheckDiskSpace(uint64 nAdditionalBytes = 0); +/** Open a block file (blk?????.dat) */ +FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); +/** Open an undo file (rev?????.dat) */ +FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); +/** Import blocks from an external file */ +bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL); +/** Initialize a new block tree database + block data on disk */ +bool InitBlockIndex(); +/** Load the block tree and coins database from disk */ +bool LoadBlockIndex(); +/** Unload database information */ +void UnloadBlockIndex(); +/** Verify consistency of the block and coin databases */ +bool VerifyDB(int nCheckLevel, int nCheckDepth); +/** Print the loaded block tree */ void PrintBlockTree(); +/** Find a block by height in the currently-connected chain */ +CBlockIndex* FindBlockByHeight(int nHeight); +/** Process protocol messages received from a given node */ bool ProcessMessages(CNode* pfrom); +/** Send queued protocol messages to be sent to a give node */ bool SendMessages(CNode* pto, bool fSendTrickle); -bool LoadExternalBlockFile(FILE* fileIn); +/** Run an instance of the script checking thread */ +void ThreadScriptCheck(); +/** Run the miner threads */ void GenerateBitcoins(bool fGenerate, CWallet* pwallet); -CBlock* CreateNewBlock(CReserveKey& reservekey); +/** Generate a new block, without valid proof-of-work */ +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); +/** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +/** Do mining precalculation */ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); +/** Check mined block */ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); +/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); +/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); +/** Get the number of active peers */ int GetNumBlocksOfPeers(); +/** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); +/** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(std::string strFor); -bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); +/** Retrieve a transaction (from memory pool, or from disk, if possible) */ +bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); +/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */ +bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew); +/** Find the best known block, and make it the tip of the block chain */ +bool ConnectBestBlock(CValidationState &state); +/** Create a new block index entry for a given block hash */ +CBlockIndex * InsertBlockIndex(uint256 hash); +/** Verify a signature */ +bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); +/** Abort with a message */ +bool AbortNode(const std::string &msg); @@ -120,56 +204,58 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); -/** Position on disk for a particular transaction. */ -class CDiskTxPos +struct CDiskBlockPos { -public: - unsigned int nFile; - unsigned int nBlockPos; - unsigned int nTxPos; + int nFile; + unsigned int nPos; - CDiskTxPos() - { + IMPLEMENT_SERIALIZE( + READWRITE(VARINT(nFile)); + READWRITE(VARINT(nPos)); + ) + + CDiskBlockPos() { SetNull(); } - CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn) - { + CDiskBlockPos(int nFileIn, unsigned int nPosIn) { nFile = nFileIn; - nBlockPos = nBlockPosIn; - nTxPos = nTxPosIn; + nPos = nPosIn; } - IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) - void SetNull() { nFile = (unsigned int) -1; nBlockPos = 0; nTxPos = 0; } - bool IsNull() const { return (nFile == (unsigned int) -1); } - - friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b) - { - return (a.nFile == b.nFile && - a.nBlockPos == b.nBlockPos && - a.nTxPos == b.nTxPos); + friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return (a.nFile == b.nFile && a.nPos == b.nPos); } - friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b) - { + friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) { return !(a == b); } - std::string ToString() const - { - if (IsNull()) - return "null"; - else - return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos); - } - - void print() const - { - printf("%s", ToString().c_str()); - } + void SetNull() { nFile = -1; nPos = 0; } + bool IsNull() const { return (nFile == -1); } }; +struct CDiskTxPos : public CDiskBlockPos +{ + unsigned int nTxOffset; // after header + + IMPLEMENT_SERIALIZE( + READWRITE(*(CDiskBlockPos*)this); + READWRITE(VARINT(nTxOffset)); + ) + + CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { + } + + CDiskTxPos() { + SetNull(); + } + + void SetNull() { + CDiskBlockPos::SetNull(); + nTxOffset = 0; + } +}; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -217,7 +303,7 @@ public: std::string ToString() const { - return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n); + return strprintf("COutPoint(%s, %u)", hash.ToString().c_str(), n); } void print() const @@ -339,7 +425,7 @@ public: scriptPubKey.clear(); } - bool IsNull() + bool IsNull() const { return (nValue == -1); } @@ -360,6 +446,8 @@ public: return !(a == b); } + bool IsDust() const; + std::string ToString() const { if (scriptPubKey.size() < 6) @@ -375,7 +463,6 @@ public: - enum GetMinFee_mode { GMF_BLOCK, @@ -383,24 +470,20 @@ enum GetMinFee_mode GMF_SEND, }; -typedef std::map > MapPrevTx; - /** The basic transaction that is broadcasted on the network and contained in - * blocks. A transaction can contain multiple inputs and outputs. + * blocks. A transaction can contain multiple inputs and outputs. */ class CTransaction { public: + static int64 nMinTxFee; + static int64 nMinRelayTxFee; static const int CURRENT_VERSION=1; int nVersion; std::vector vin; std::vector vout; unsigned int nLockTime; - // Denial-of-service detection: - mutable int nDoS; - bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } - CTransaction() { SetNull(); @@ -421,7 +504,6 @@ public: vin.clear(); vout.clear(); nLockTime = 0; - nDoS = 0; // Denial-of-service prevention } bool IsNull() const @@ -488,18 +570,21 @@ public: /** Check for standard transaction types @return True if all outputs (scriptPubKeys) use only standard transaction forms */ - bool IsStandard() const; + bool IsStandard(std::string& strReason) const; + bool IsStandard() const + { + std::string strReason; + return IsStandard(strReason); + } /** 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 - @see CTransaction::FetchInputs */ - bool AreInputsStandard(const MapPrevTx& mapInputs) const; + bool AreInputsStandard(CCoinsViewCache& mapInputs) const; /** Count ECDSA signature operations the old-fashioned (pre-0.6) way @return number of sigops this transaction's outputs will produce when spent - @see CTransaction::FetchInputs */ unsigned int GetLegacySigOpCount() const; @@ -507,9 +592,8 @@ public: @param[in] mapInputs Map of previous transactions that have outputs we're spending @return maximum number of sigops required to validate this transaction's inputs - @see CTransaction::FetchInputs */ - unsigned int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const; + unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const; /** Amount of bitcoins spent by this transaction. @return sum of all outputs (note: does not include fees) @@ -532,88 +616,20 @@ public: @param[in] mapInputs Map of previous transactions that have outputs we're spending @return Sum of value of all inputs (scriptSigs) - @see CTransaction::FetchInputs */ - int64 GetValueIn(const MapPrevTx& mapInputs) const; + int64 GetValueIn(CCoinsViewCache& mapInputs) const; static bool AllowFree(double dPriority) { // Large (in bytes) low-priority (new, small-coin) transactions // need a fee. - return dPriority > COIN * 2880 / 250; // CasinoCoin: 2880 blocks found a day. Priority cutoff is 1 casinocoin day / 250 bytes. + return dPriority > COIN * 2880 / 250; // CasinoCoin: 2880 blocks found a day. Priority cutoff is 1 casinocoin day / 250 bytes. } - int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const - { - // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE - int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE; +// Apply the effects of this transaction on the UTXO set represented by view +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash); - unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); - unsigned int nNewBlockSize = nBlockSize + nBytes; - int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; - - if (fAllowFree) - { - if (nBlockSize == 1) - { - // Transactions under 10K are free - // (about 4500bc if made of 50bc inputs) - if (nBytes < 10000) - nMinFee = 0; - } - else - { - // Free transaction area - if (nNewBlockSize < 27000) - nMinFee = 0; - } - } - - // To limit dust spam, add MIN_TX_FEE/MIN_RELAY_TX_FEE for any output that is less than 0.01 - BOOST_FOREACH(const CTxOut& txout, vout) - if (txout.nValue < CENT) - nMinFee += nBaseFee; - - // Raise the price as the block approaches full - if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) - { - if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN) - return MAX_MONEY; - nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize); - } - - if (!MoneyRange(nMinFee)) - nMinFee = MAX_MONEY; - return nMinFee; - } - - - bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) - { - CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); - - // Read transaction - if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) - return error("CTransaction::ReadFromDisk() : fseek failed"); - - try { - filein >> *this; - } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); - } - - // Return file pointer - if (pfileRet) - { - if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) - return error("CTransaction::ReadFromDisk() : second fseek failed"); - *pfileRet = filein.release(); - } - return true; - } + int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const; friend bool operator==(const CTransaction& a, const CTransaction& b) { @@ -632,8 +648,8 @@ public: std::string ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n", - GetHash().ToString().substr(0,10).c_str(), + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", + GetHash().ToString().c_str(), nVersion, vin.size(), vout.size(), @@ -651,50 +667,456 @@ public: } - bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet); - bool ReadFromDisk(CTxDB& txdb, COutPoint prevout); - bool ReadFromDisk(COutPoint prevout); - bool DisconnectInputs(CTxDB& txdb); + // Check whether all prevouts of this transaction are present in the UTXO set represented by view + bool HaveInputs(CCoinsViewCache &view) const; - /** Fetch from memory and/or disk. inputsRet keys are transaction hashes. + // Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) + // This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it + // instead of being performed inline. + bool CheckInputs(CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true, + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, + std::vector *pvChecks = NULL) const; - @param[in] txdb Transaction database - @param[in] mapTestPool List of pending changes to the transaction index database - @param[in] fBlock True if being called to add a new best-block to the chain - @param[in] fMiner True if being called by CreateNewBlock - @param[out] inputsRet Pointers to this transaction's inputs - @param[out] fInvalid returns true if transaction is invalid - @return Returns true if all inputs are in txdb or mapTestPool - */ - bool FetchInputs(CTxDB& txdb, const std::map& mapTestPool, - bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid); + // Apply the effects of this transaction on the UTXO set represented by view + void UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const; - /** Sanity check previous transactions, then, if all checks succeed, - mark them as spent by this transaction. + // Context-independent validity checks + bool CheckTransaction(CValidationState &state) const; - @param[in] inputs Previous transactions (from FetchInputs) - @param[out] mapTestPool Keeps track of inputs that need to be updated on disk - @param[in] posThisTx Position of this transaction on disk - @param[in] pindexBlock - @param[in] fBlock true if called from ConnectBlock - @param[in] fMiner true if called from CreateNewBlock - @param[in] fStrictPayToScriptHash true if fully validating p2sh transactions - @return Returns true if all checks succeed - */ - bool ConnectInputs(MapPrevTx inputs, - std::map& mapTestPool, const CDiskTxPos& posThisTx, - const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash=true); - bool ClientConnectInputs(); - bool CheckTransaction() const; - bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); + // Try to accept this transaction into the memory pool + bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL); protected: - const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const; + static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs); }; +/** wrapper for CTxOut that provides a more compact serialization */ +class CTxOutCompressor +{ +private: + CTxOut &txout; +public: + static uint64 CompressAmount(uint64 nAmount); + static uint64 DecompressAmount(uint64 nAmount); + CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { } + IMPLEMENT_SERIALIZE(({ + if (!fRead) { + uint64 nVal = CompressAmount(txout.nValue); + READWRITE(VARINT(nVal)); + } else { + uint64 nVal = 0; + READWRITE(VARINT(nVal)); + txout.nValue = DecompressAmount(nVal); + } + CScriptCompressor cscript(REF(txout.scriptPubKey)); + READWRITE(cscript); + });) +}; + +/** Undo information for a CTxIn + * + * Contains the prevout's CTxOut being spent, and if this was the + * last output of the affected transaction, its metadata as well + * (coinbase or not, height, transaction version) + */ +class CTxInUndo +{ +public: + CTxOut txout; // the txout data before being spent + bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase + unsigned int nHeight; // if the outpoint was the last unspent: its height + int nVersion; // if the outpoint was the last unspent: its version + + CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {} + CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { } + + 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 + void Serialize(Stream &s, int nType, int nVersion) const { + ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion); + if (nHeight > 0) + ::Serialize(s, VARINT(this->nVersion), nType, nVersion); + ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion); + } + + template + void Unserialize(Stream &s, int nType, int nVersion) { + unsigned int nCode = 0; + ::Unserialize(s, VARINT(nCode), nType, nVersion); + nHeight = nCode / 2; + fCoinBase = nCode & 1; + if (nHeight > 0) + ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); + ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion); + } +}; + +/** Undo information for a CTransaction */ +class CTxUndo +{ +public: + // undo information for all txins + std::vector vprevout; + + IMPLEMENT_SERIALIZE( + READWRITE(vprevout); + ) +}; + +/** Undo information for a CBlock */ +class CBlockUndo +{ +public: + std::vector vtxundo; // for all but the coinbase + + IMPLEMENT_SERIALIZE( + READWRITE(vtxundo); + ) + + bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) + { + // Open history file to append + CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("CBlockUndo::WriteToDisk() : OpenUndoFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(*this); + fileout << FLATDATA(pchMessageStart) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("CBlockUndo::WriteToDisk() : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << *this; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << *this; + fileout << hasher.GetHash(); + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; + } + + bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) + { + // Open history file to read + CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CBlockUndo::ReadFromDisk() : OpenBlockFile failed"); + + // Read block + uint256 hashChecksum; + try { + filein >> *this; + filein >> hashChecksum; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << *this; + if (hashChecksum != hasher.GetHash()) + return error("CBlockUndo::ReadFromDisk() : checksum mismatch"); + + return true; + } +}; + +/** pruned version of CTransaction: only retains metadata and unspent transaction outputs + * + * Serialized format: + * - VARINT(nVersion) + * - VARINT(nCode) + * - unspentness bitvector, for vout[2] and further; least significant byte first + * - the non-spent CTxOuts (via CTxOutCompressor) + * - VARINT(nHeight) + * + * The nCode value consists of: + * - bit 1: IsCoinBase() + * - bit 2: vout[0] is not spent + * - bit 4: vout[1] is not spent + * - The higher bits encode N, the number of non-zero bytes in the following bitvector. + * - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at + * least one non-spent output). + * + * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e + * <><><--------------------------------------------><----> + * | \ | / + * version code vout[1] height + * + * - version = 1 + * - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow) + * - unspentness bitvector: as 0 non-zero bytes follow, it has length 0 + * - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35 + * * 8358: compact amount representation for 60000000000 (600 BTC) + * * 00: special txout type pay-to-pubkey-hash + * * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160 + * - height = 203998 + * + * + * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b + * <><><--><--------------------------------------------------><----------------------------------------------><----> + * / \ \ | | / + * version code unspentness vout[4] vout[16] height + * + * - version = 1 + * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent, + * 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow) + * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent + * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee + * * 86ef97d579: compact amount representation for 234925952 (2.35 BTC) + * * 00: special txout type pay-to-pubkey-hash + * * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160 + * - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4 + * * bbd123: compact amount representation for 110397 (0.001 BTC) + * * 00: special txout type pay-to-pubkey-hash + * * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160 + * - height = 120891 + */ +class CCoins +{ +public: + // whether transaction is a coinbase + bool fCoinBase; + + // unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped + std::vector vout; + + // at which height this transaction was included in the active block chain + int nHeight; + + // version of the CTransaction; accesses to this value should probably check for nHeight as well, + // as new tx version will probably only be introduced at certain heights + int nVersion; + + // construct a CCoins from a CTransaction, at a given height + CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) { } + + // empty constructor + CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { } + + // remove spent outputs at the end of vout + void Cleanup() { + while (vout.size() > 0 && vout.back().IsNull()) + vout.pop_back(); + if (vout.empty()) + std::vector().swap(vout); + } + + void swap(CCoins &to) { + std::swap(to.fCoinBase, fCoinBase); + to.vout.swap(vout); + std::swap(to.nHeight, nHeight); + std::swap(to.nVersion, nVersion); + } + + // equality test + friend bool operator==(const CCoins &a, const CCoins &b) { + return a.fCoinBase == b.fCoinBase && + a.nHeight == b.nHeight && + a.nVersion == b.nVersion && + a.vout == b.vout; + } + friend bool operator!=(const CCoins &a, const CCoins &b) { + return !(a == b); + } + + // calculate number of bytes for the bitmask, and its number of non-zero bytes + // each bit in the bitmask represents the availability of one output, but the + // availabilities of the first two outputs are encoded separately + void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { + unsigned int nLastUsedByte = 0; + for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { + bool fZero = true; + for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { + if (!vout[2+b*8+i].IsNull()) { + fZero = false; + continue; + } + } + if (!fZero) { + nLastUsedByte = b + 1; + nNonzeroBytes++; + } + } + nBytes += nLastUsedByte; + } + + bool IsCoinBase() const { + 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 + void Serialize(Stream &s, int nType, int nVersion) const { + unsigned int nMaskSize = 0, nMaskCode = 0; + CalcMaskSize(nMaskSize, nMaskCode); + bool fFirst = vout.size() > 0 && !vout[0].IsNull(); + bool fSecond = vout.size() > 1 && !vout[1].IsNull(); + assert(fFirst || fSecond || nMaskCode); + unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); + // version + ::Serialize(s, VARINT(this->nVersion), nType, nVersion); + // header code + ::Serialize(s, VARINT(nCode), nType, nVersion); + // spentness bitmask + for (unsigned int b = 0; b + void Unserialize(Stream &s, int nType, int nVersion) { + unsigned int nCode = 0; + // version + ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); + // header code + ::Unserialize(s, VARINT(nCode), nType, nVersion); + fCoinBase = nCode & 1; + std::vector vAvail(2, false); + vAvail[0] = nCode & 2; + vAvail[1] = nCode & 4; + unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1); + // spentness bitmask + while (nMaskCode > 0) { + unsigned char chAvail = 0; + ::Unserialize(s, chAvail, nType, nVersion); + for (unsigned int p = 0; p < 8; p++) { + bool f = (chAvail & (1 << p)) != 0; + vAvail.push_back(f); + } + if (chAvail != 0) + nMaskCode--; + } + // txouts themself + vout.assign(vAvail.size(), CTxOut()); + for (unsigned int i = 0; i < vAvail.size(); i++) { + if (vAvail[i]) + ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion); + } + // coinbase height + ::Unserialize(s, VARINT(nHeight), nType, nVersion); + Cleanup(); + } + + // mark an outpoint spent, and construct undo information + bool Spend(const COutPoint &out, CTxInUndo &undo) { + if (out.n >= vout.size()) + return false; + if (vout[out.n].IsNull()) + return false; + undo = CTxInUndo(vout[out.n]); + vout[out.n].SetNull(); + Cleanup(); + if (vout.size() == 0) { + undo.nHeight = nHeight; + undo.fCoinBase = fCoinBase; + undo.nVersion = this->nVersion; + } + return true; + } + + // mark a vout spent + bool Spend(int nPos) { + CTxInUndo undo; + COutPoint out(0, nPos); + return Spend(out, undo); + } + + // check whether a particular output is still available + bool IsAvailable(unsigned int nPos) const { + return (nPos < vout.size() && !vout[nPos].IsNull()); + } + + // check whether the entire CCoins is spent + // note that only !IsPruned() CCoins can be serialized + bool IsPruned() const { + BOOST_FOREACH(const CTxOut &out, vout) + if (!out.IsNull()) + return false; + return true; + } +}; + +/** Closure representing one script verification + * Note that this stores references to the spending transaction */ +class CScriptCheck +{ +private: + CScript scriptPubKey; + const CTransaction *ptxTo; + unsigned int nIn; + unsigned int nFlags; + int nHashType; + +public: + CScriptCheck() {} + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int nHashTypeIn) : + scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { } + + bool operator()() const; + + void swap(CScriptCheck &check) { + scriptPubKey.swap(check.scriptPubKey); + std::swap(ptxTo, check.ptxTo); + std::swap(nIn, check.nIn); + std::swap(nFlags, check.nFlags); + std::swap(nHashType, check.nHashType); + } +}; /** A transaction with a merkle branch linking it to the block chain. */ class CMerkleTx : public CTransaction @@ -741,86 +1163,122 @@ public: int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } bool IsInMainChain() const { return GetDepthInMainChain() > 0; } int GetBlocksToMaturity() const; - bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true); - bool AcceptToMemoryPool(); + bool AcceptToMemoryPool(bool fCheckInputs=true, bool fLimitFree=true); }; -/** A txdb record that contains the disk location of a transaction and the - * locations of transactions that spend its outputs. vSpent is really only - * used as a flag, but having the location is very helpful for debugging. + +/** Data structure that represents a partial merkle tree. + * + * It respresents a subset of the txid's of a known block, in a way that + * allows recovery of the list of txid's and the merkle root, in an + * authenticated way. + * + * The encoding works as follows: we traverse the tree in depth-first order, + * 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, 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. + * + * The serialization is fixed and provides a hard guarantee about the + * encoded size: + * + * SIZE <= 10 + ceil(32.25*N) + * + * Where N represents the number of leaf nodes of the partial tree. N itself + * is bounded by: + * + * N <= total_transactions + * N <= 1 + matched_transactions*tree_height + * + * The serialization format: + * - uint32 total_transactions (4 bytes) + * - varint number of hashes (1-3 bytes) + * - uint256[] hashes in depth-first order (<= 32*N bytes) + * - varint number of bytes of flag bits (1-3 bytes) + * - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits) + * The size constraints follow from this. */ -class CTxIndex +class CPartialMerkleTree { +protected: + // the total number of transactions in the block + unsigned int nTransactions; + + // node-is-parent-of-matched-txid bits + std::vector vBits; + + // txids and internal hashes + std::vector vHash; + + // flag set when encountering invalid data + bool fBad; + + // helper function to efficiently calculate the number of nodes at given height in the merkle tree + unsigned int CalcTreeWidth(int height) { + return (nTransactions+(1 << height)-1) >> height; + } + + // calculate the hash of a node in the merkle tree (at leaf level: the txid's themself) + uint256 CalcHash(int height, unsigned int pos, const std::vector &vTxid); + + // recursive function that traverses tree nodes, storing the data as bits and hashes + void TraverseAndBuild(int height, unsigned int pos, const std::vector &vTxid, const std::vector &vMatch); + + // recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild. + // it returns the hash of the respective node. + uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch); + public: - CDiskTxPos pos; - std::vector vSpent; - CTxIndex() - { - SetNull(); - } - - CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs) - { - pos = posIn; - vSpent.resize(nOutputs); - } - - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(pos); - READWRITE(vSpent); + // serialization implementation + IMPLEMENT_SERIALIZE( + READWRITE(nTransactions); + READWRITE(vHash); + std::vector vBytes; + if (fRead) { + READWRITE(vBytes); + CPartialMerkleTree &us = *(const_cast(this)); + us.vBits.resize(vBytes.size() * 8); + for (unsigned int p = 0; p < us.vBits.size(); p++) + us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0; + us.fBad = false; + } else { + vBytes.resize((vBits.size()+7)/8); + for (unsigned int p = 0; p < vBits.size(); p++) + vBytes[p / 8] |= vBits[p] << (p % 8); + READWRITE(vBytes); + } ) - void SetNull() - { - pos.SetNull(); - vSpent.clear(); - } + // Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them + CPartialMerkleTree(const std::vector &vTxid, const std::vector &vMatch); - bool IsNull() - { - return pos.IsNull(); - } + CPartialMerkleTree(); - friend bool operator==(const CTxIndex& a, const CTxIndex& b) - { - return (a.pos == b.pos && - a.vSpent == b.vSpent); - } - - friend bool operator!=(const CTxIndex& a, const CTxIndex& b) - { - return !(a == b); - } - int GetDepthInMainChain() const; - + // extract the matching txid's represented by this partial merkle tree. + // returns the merkle root, or 0 in case of failure + uint256 ExtractMatches(std::vector &vMatch); }; - - - /** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work * requirements. When they solve the proof-of-work, they broadcast the block * to everyone and the block is added to the block chain. The first transaction * in the block is a special one that creates a new coin owned by the creator * of the block. - * - * Blocks are appended to blk0001.dat files on disk. Their location on disk - * is indexed by CBlockIndex objects in memory. */ -class CBlock +class CBlockHeader { public: // header - static const int CURRENT_VERSION=1; + static const int CURRENT_VERSION=2; int nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; @@ -828,17 +1286,7 @@ public: unsigned int nBits; unsigned int nNonce; - // network and disk - std::vector vtx; - - // memory only - mutable std::vector vMerkleTree; - - // Denial-of-service detection: - mutable int nDoS; - bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } - - CBlock() + CBlockHeader() { SetNull(); } @@ -852,25 +1300,16 @@ public: READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); - - // ConnectBlock depends on vtx being last so it can calculate offset - if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY))) - READWRITE(vtx); - else if (fRead) - const_cast(this)->vtx.clear(); ) void SetNull() { - nVersion = CBlock::CURRENT_VERSION; + nVersion = CBlockHeader::CURRENT_VERSION; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; nBits = 0; nNonce = 0; - vtx.clear(); - vMerkleTree.clear(); - nDoS = 0; } bool IsNull() const @@ -883,6 +1322,47 @@ public: return Hash(BEGIN(nVersion), END(nNonce)); } + int64 GetBlockTime() const + { + return (int64)nTime; + } + + void UpdateTime(const CBlockIndex* pindexPrev); +}; + +class CBlock : public CBlockHeader +{ +public: + // network and disk + std::vector vtx; + + // memory only + mutable std::vector vMerkleTree; + + CBlock() + { + SetNull(); + } + + CBlock(const CBlockHeader &header) + { + SetNull(); + *((CBlockHeader*)this) = header; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(*(CBlockHeader*)this); + READWRITE(vtx); + ) + + void SetNull() + { + CBlockHeader::SetNull(); + vtx.clear(); + vMerkleTree.clear(); + } + uint256 GetPoWHash() const { uint256 thash; @@ -890,14 +1370,18 @@ public: return thash; } - int64 GetBlockTime() const + CBlockHeader GetBlockHeader() const { - return (int64)nTime; + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrevBlock; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; } - void UpdateTime(const CBlockIndex* pindexPrev); - - uint256 BuildMerkleTree() const { vMerkleTree.clear(); @@ -917,6 +1401,12 @@ public: return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); } + const uint256 &GetTxHash(unsigned int nIndex) const { + assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first + assert(nIndex < vtx.size()); + return vMerkleTree[nIndex]; + } + std::vector GetMerkleBranch(int nIndex) const { if (vMerkleTree.empty()) @@ -948,13 +1438,12 @@ public: return hash; } - - bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet) + bool WriteToDisk(CDiskBlockPos &pos) { // Open history file to append - CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); + CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) - return error("CBlock::WriteToDisk() : AppendBlockFile failed"); + return error("CBlock::WriteToDisk() : OpenBlockFile failed"); // Write index header unsigned int nSize = fileout.GetSerializeSize(*this); @@ -964,27 +1453,25 @@ public: long fileOutPos = ftell(fileout); if (fileOutPos < 0) return error("CBlock::WriteToDisk() : ftell failed"); - nBlockPosRet = fileOutPos; + pos.nPos = (unsigned int)fileOutPos; fileout << *this; // Flush stdio buffers and commit to disk before returning fflush(fileout); - if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) + if (!IsInitialBlockDownload()) FileCommit(fileout); return true; } - bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true) + bool ReadFromDisk(const CDiskBlockPos &pos) { SetNull(); // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); + CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); - if (!fReadTransactions) - filein.nType |= SER_BLOCKHEADERONLY; // Read block try { @@ -1005,12 +1492,13 @@ public: void print() const { - printf("CBlock(hash=%s, PoW=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n", - GetHash().ToString().substr(0,20).c_str(), - GetPoWHash().ToString().substr(0,20).c_str(), + printf("CBlock(hash=%s, input=%s, PoW=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + GetHash().ToString().c_str(), + HexStr(BEGIN(nVersion),BEGIN(nVersion)+80,false).c_str(), + GetPoWHash().ToString().c_str(), nVersion, - hashPrevBlock.ToString().substr(0,20).c_str(), - hashMerkleRoot.ToString().substr(0,10).c_str(), + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), nTime, nBits, nNonce, vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) @@ -1020,27 +1508,112 @@ public: } printf(" vMerkleTree: "); for (unsigned int i = 0; i < vMerkleTree.size(); i++) - printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str()); + printf("%s ", vMerkleTree[i].ToString().c_str()); printf("\n"); } - bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); - bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); - bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); - bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew); - bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); - bool CheckBlock() const; - bool AcceptBlock(); + /** 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(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL); -private: - bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew); + // Apply the effects of this block (with given index) on the UTXO set represented by coins + bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); + + // Read a block from disk + bool ReadFromDisk(const CBlockIndex* pindex); + + // Add this block to the block index, and if necessary, switch the active block chain to this + bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos); + + // Context-independent validity checks + bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; + + // Store block on disk + // if dbp is provided, the file is known to already reside on disk + bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL); }; +class CBlockFileInfo +{ +public: + unsigned int nBlocks; // number of blocks stored in file + unsigned int nSize; // number of used bytes of block file + unsigned int nUndoSize; // number of used bytes in the undo file + unsigned int nHeightFirst; // lowest height of block in file + unsigned int nHeightLast; // highest height of block in file + uint64 nTimeFirst; // earliest time of block in file + uint64 nTimeLast; // latest time of block in file + + IMPLEMENT_SERIALIZE( + READWRITE(VARINT(nBlocks)); + READWRITE(VARINT(nSize)); + READWRITE(VARINT(nUndoSize)); + READWRITE(VARINT(nHeightFirst)); + READWRITE(VARINT(nHeightLast)); + READWRITE(VARINT(nTimeFirst)); + READWRITE(VARINT(nTimeLast)); + ) + + void SetNull() { + nBlocks = 0; + nSize = 0; + nUndoSize = 0; + nHeightFirst = 0; + nHeightLast = 0; + nTimeFirst = 0; + nTimeLast = 0; + } + + CBlockFileInfo() { + SetNull(); + } + + std::string ToString() const { + return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str()); + } + + // update statistics (does not update nSize) + void AddBlock(unsigned int nHeightIn, uint64 nTimeIn) { + if (nBlocks==0 || nHeightFirst > nHeightIn) + nHeightFirst = nHeightIn; + if (nBlocks==0 || nTimeFirst > nTimeIn) + nTimeFirst = nTimeIn; + nBlocks++; + if (nHeightIn > nHeightFirst) + nHeightLast = nHeightIn; + if (nTimeIn > nTimeLast) + nTimeLast = nTimeIn; + } +}; + +extern CCriticalSection cs_LastBlockFile; +extern CBlockFileInfo infoLastBlockFile; +extern int nLastBlockFile; + +enum BlockStatus { + BLOCK_VALID_UNKNOWN = 0, + BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future + BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint + BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root + BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30 + BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok + BLOCK_VALID_MASK = 7, + + BLOCK_HAVE_DATA = 8, // full block available in blk*.dat + BLOCK_HAVE_UNDO = 16, // undo data available in rev*.dat + BLOCK_HAVE_MASK = 24, + + BLOCK_FAILED_VALID = 32, // stage after last reached validness failed + BLOCK_FAILED_CHILD = 64, // descends from failed block + BLOCK_FAILED_MASK = 96 +}; /** The block chain is a tree shaped structure starting with the * genesis block at the root, with each block potentially having multiple @@ -1052,13 +1625,39 @@ private: class CBlockIndex { public: + // pointer to the hash of the block, if any. memory is owned by this CBlockIndex const uint256* phashBlock; + + // pointer to the index of the predecessor of this block CBlockIndex* pprev; + + // (memory only) pointer to the index of the *active* successor of this block CBlockIndex* pnext; - unsigned int nFile; - unsigned int nBlockPos; + + // height of the entry in the chain. The genesis block has height 0 int nHeight; - CBigNum bnChainWork; + + // Which # file this block is stored in (blk?????.dat) + int nFile; + + // Byte offset within blk?????.dat where this block's data is stored + unsigned int nDataPos; + + // Byte offset within rev?????.dat where this block's undo data is stored + unsigned int nUndoPos; + + // (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block + uint256 nChainWork; + + // Number of transactions in this block. + // Note: in a potential headers-first mode, this number cannot be relied upon + unsigned int nTx; + + // (memory only) Number of transactions in the chain up to and including this block + unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030 + + // Verification status of this block. See enum BlockStatus + unsigned int nStatus; // block header int nVersion; @@ -1073,10 +1672,14 @@ public: phashBlock = NULL; pprev = NULL; pnext = NULL; - nFile = 0; - nBlockPos = 0; nHeight = 0; - bnChainWork = 0; + nFile = 0; + nDataPos = 0; + nUndoPos = 0; + nChainWork = 0; + nTx = 0; + nChainTx = 0; + nStatus = 0; nVersion = 0; hashMerkleRoot = 0; @@ -1085,15 +1688,19 @@ public: nNonce = 0; } - CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block) + CBlockIndex(CBlockHeader& block) { phashBlock = NULL; pprev = NULL; pnext = NULL; - nFile = nFileIn; - nBlockPos = nBlockPosIn; nHeight = 0; - bnChainWork = 0; + nFile = 0; + nDataPos = 0; + nUndoPos = 0; + nChainWork = 0; + nTx = 0; + nChainTx = 0; + nStatus = 0; nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; @@ -1102,9 +1709,27 @@ public: nNonce = block.nNonce; } - CBlock GetBlockHeader() const + CDiskBlockPos GetBlockPos() const { + CDiskBlockPos ret; + if (nStatus & BLOCK_HAVE_DATA) { + ret.nFile = nFile; + ret.nPos = nDataPos; + } + return ret; + } + + CDiskBlockPos GetUndoPos() const { + CDiskBlockPos ret; + if (nStatus & BLOCK_HAVE_UNDO) { + ret.nFile = nFile; + ret.nPos = nUndoPos; + } + return ret; + } + + CBlockHeader GetBlockHeader() const { - CBlock block; + CBlockHeader block; block.nVersion = nVersion; if (pprev) block.hashPrevBlock = pprev->GetBlockHash(); @@ -1141,7 +1766,9 @@ public: bool CheckIndex() const { - return true; // CheckProofOfWork(GetBlockHash(), nBits); + /** Scrypt is used for block proof-of-work, but for purposes of performance the index internally uses sha256. + * This check was considered unneccessary given the other safeguards like the genesis and checkpoints. */ + return true; // return CheckProofOfWork(GetBlockHash(), nBits); } enum { nMedianTimeSpan=11 }; @@ -1172,14 +1799,19 @@ public: return pindex->GetMedianTimePast(); } - + /** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last nToCheck blocks, starting at pstart and going backwards. + */ + static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, + unsigned int nRequired, unsigned int nToCheck); std::string ToString() const { - return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, pnext, nFile, nBlockPos, nHeight, - hashMerkleRoot.ToString().substr(0,10).c_str(), - GetBlockHash().ToString().substr(0,20).c_str()); + return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)", + pprev, pnext, nHeight, + hashMerkleRoot.ToString().c_str(), + GetBlockHash().ToString().c_str()); } void print() const @@ -1188,6 +1820,19 @@ public: } }; +struct CBlockIndexWorkComparator +{ + bool operator()(CBlockIndex *pa, CBlockIndex *pb) { + if (pa->nChainWork > pb->nChainWork) return false; + if (pa->nChainWork < pb->nChainWork) return true; + + if (pa->GetBlockHash() < pb->GetBlockHash()) return false; + if (pa->GetBlockHash() > pb->GetBlockHash()) return true; + + return false; // identical blocks + } +}; + /** Used to marshal pointers into hashes for db storage. */ @@ -1195,29 +1840,29 @@ class CDiskBlockIndex : public CBlockIndex { public: uint256 hashPrev; - uint256 hashNext; - CDiskBlockIndex() - { + CDiskBlockIndex() { hashPrev = 0; - hashNext = 0; } - explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) - { + explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) { hashPrev = (pprev ? pprev->GetBlockHash() : 0); - hashNext = (pnext ? pnext->GetBlockHash() : 0); } IMPLEMENT_SERIALIZE ( if (!(nType & SER_GETHASH)) - READWRITE(nVersion); + READWRITE(VARINT(nVersion)); - READWRITE(hashNext); - READWRITE(nFile); - READWRITE(nBlockPos); - READWRITE(nHeight); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nStatus)); + READWRITE(VARINT(nTx)); + if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) + READWRITE(VARINT(nFile)); + if (nStatus & BLOCK_HAVE_DATA) + READWRITE(VARINT(nDataPos)); + if (nStatus & BLOCK_HAVE_UNDO) + READWRITE(VARINT(nUndoPos)); // block header READWRITE(this->nVersion); @@ -1230,7 +1875,7 @@ public: uint256 GetBlockHash() const { - CBlock block; + CBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; @@ -1245,10 +1890,9 @@ public: { std::string str = "CDiskBlockIndex("; str += CBlockIndex::ToString(); - str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", + str += strprintf("\n hashBlock=%s, hashPrev=%s)", GetBlockHash().ToString().c_str(), - hashPrev.ToString().substr(0,20).c_str(), - hashNext.ToString().substr(0,20).c_str()); + hashPrev.ToString().c_str()); return str; } @@ -1258,6 +1902,57 @@ public: } }; +/** Capture information about block/transaction validation */ +class CValidationState { +private: + enum mode_state { + MODE_VALID, // everything ok + MODE_INVALID, // network rule violation (DoS value may be set) + MODE_ERROR, // run-time error + } mode; + int nDoS; + bool corruptionPossible; +public: + CValidationState() : mode(MODE_VALID), nDoS(0), corruptionPossible(false) {} + bool DoS(int level, bool ret = false, bool corruptionIn = false) { + if (mode == MODE_ERROR) + return ret; + nDoS += level; + mode = MODE_INVALID; + corruptionPossible = corruptionIn; + return ret; + } + bool Invalid(bool ret = false) { + return DoS(0, ret); + } + bool Error() { + mode = MODE_ERROR; + return false; + } + bool Abort(const std::string &msg) { + AbortNode(msg); + return Error(); + } + bool IsValid() { + return mode == MODE_VALID; + } + bool IsInvalid() { + return mode == MODE_INVALID; + } + bool IsError() { + return mode == MODE_ERROR; + } + bool IsInvalid(int &nDoSOut) { + if (IsInvalid()) { + nDoSOut = nDoS; + return true; + } + return false; + } + bool CorruptionPossible() { + return corruptionPossible; + } +}; @@ -1399,212 +2094,6 @@ public: - -/** Alerts are for notifying old versions if they become too obsolete and - * need to upgrade. The message is displayed in the status bar. - * Alert messages are broadcast as a vector of signed data. Unserializing may - * not read the entire buffer if the alert is for a newer version, but older - * versions can still relay the original data. - */ -class CUnsignedAlert -{ -public: - int nVersion; - int64 nRelayUntil; // when newer nodes stop relaying to newer nodes - int64 nExpiration; - int nID; - int nCancel; - std::set setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set setSubVer; // empty matches all - int nPriority; - - // Actions - std::string strComment; - std::string strStatusBar; - std::string strReserved; - - IMPLEMENT_SERIALIZE - ( - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(nRelayUntil); - READWRITE(nExpiration); - READWRITE(nID); - READWRITE(nCancel); - READWRITE(setCancel); - READWRITE(nMinVer); - READWRITE(nMaxVer); - READWRITE(setSubVer); - READWRITE(nPriority); - - READWRITE(strComment); - READWRITE(strStatusBar); - READWRITE(strReserved); - ) - - void SetNull() - { - nVersion = 1; - nRelayUntil = 0; - nExpiration = 0; - nID = 0; - nCancel = 0; - setCancel.clear(); - nMinVer = 0; - nMaxVer = 0; - setSubVer.clear(); - nPriority = 0; - - strComment.clear(); - strStatusBar.clear(); - strReserved.clear(); - } - - std::string ToString() const - { - std::string strSetCancel; - BOOST_FOREACH(int n, setCancel) - strSetCancel += strprintf("%d ", n); - std::string strSetSubVer; - BOOST_FOREACH(std::string str, setSubVer) - strSetSubVer += "\"" + str + "\" "; - return strprintf( - "CAlert(\n" - " nVersion = %d\n" - " nRelayUntil = %"PRI64d"\n" - " nExpiration = %"PRI64d"\n" - " nID = %d\n" - " nCancel = %d\n" - " setCancel = %s\n" - " nMinVer = %d\n" - " nMaxVer = %d\n" - " setSubVer = %s\n" - " nPriority = %d\n" - " strComment = \"%s\"\n" - " strStatusBar = \"%s\"\n" - ")\n", - nVersion, - nRelayUntil, - nExpiration, - nID, - nCancel, - strSetCancel.c_str(), - nMinVer, - nMaxVer, - strSetSubVer.c_str(), - nPriority, - strComment.c_str(), - strStatusBar.c_str()); - } - - void print() const - { - printf("%s", ToString().c_str()); - } -}; - -/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ -class CAlert : public CUnsignedAlert -{ -public: - std::vector vchMsg; - std::vector vchSig; - - CAlert() - { - SetNull(); - } - - IMPLEMENT_SERIALIZE - ( - READWRITE(vchMsg); - READWRITE(vchSig); - ) - - void SetNull() - { - CUnsignedAlert::SetNull(); - vchMsg.clear(); - vchSig.clear(); - } - - bool IsNull() const - { - return (nExpiration == 0); - } - - uint256 GetHash() const - { - return SerializeHash(*this); - } - - bool IsInEffect() const - { - return (GetAdjustedTime() < nExpiration); - } - - bool Cancels(const CAlert& alert) const - { - if (!IsInEffect()) - return false; // this was a no-op before 31403 - return (alert.nID <= nCancel || setCancel.count(alert.nID)); - } - - bool AppliesTo(int nVersion, std::string strSubVerIn) const - { - // TODO: rework for client-version-embedded-in-strSubVer ? - return (IsInEffect() && - nMinVer <= nVersion && nVersion <= nMaxVer && - (setSubVer.empty() || setSubVer.count(strSubVerIn))); - } - - bool AppliesToMe() const - { - return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); - } - - bool RelayTo(CNode* pnode) const - { - if (!IsInEffect()) - return false; - // returns true if wasn't already contained in the set - if (pnode->setKnown.insert(GetHash()).second) - { - if (AppliesTo(pnode->nVersion, pnode->strSubVer) || - AppliesToMe() || - GetAdjustedTime() < nRelayUntil) - { - pnode->PushMessage("alert", *this); - return true; - } - } - return false; - } - - bool CheckSignature() - { - CKey key; - if (!key.SetPubKey(ParseHex("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"))) - return error("CAlert::CheckSignature() : SetPubKey failed"); - if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - return error("CAlert::CheckSignature() : verify signature failed"); - - // Now unserialize the data - CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); - sMsg >> *(CUnsignedAlert*)this; - return true; - } - - bool ProcessAlert(); - - /* - * Get copy of (active) alert object by hash. Returns a null alert if it is not found. - */ - static CAlert getAlertByHash(const uint256 &hash); -}; - class CTxMemPool { public: @@ -1612,11 +2101,13 @@ public: std::map mapTx; std::map mapNextTx; - bool accept(CTxDB& txdb, CTransaction &tx, - bool fCheckInputs, bool* pfMissingInputs); - bool addUnchecked(const uint256& hash, CTransaction &tx); - bool remove(CTransaction &tx); + bool accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs); + bool addUnchecked(const uint256& hash, const CTransaction &tx); + bool remove(const CTransaction &tx, bool fRecursive = false); + bool removeConflicts(const CTransaction &tx); + void clear(); void queryHashes(std::vector& vtxid); + void pruneSpent(const uint256& hash, CCoins &coins); unsigned long size() { @@ -1637,4 +2128,160 @@ public: extern CTxMemPool mempool; +struct CCoinsStats +{ + int nHeight; + uint256 hashBlock; + uint64 nTransactions; + uint64 nTransactionOutputs; + uint64 nSerializedSize; + uint256 hashSerialized; + int64 nTotalAmount; + + CCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0), nTotalAmount(0) {} +}; + +/** Abstract view on the open txout dataset. */ +class CCoinsView +{ +public: + // Retrieve the CCoins (unspent transaction outputs) for a given txid + virtual bool GetCoins(const uint256 &txid, CCoins &coins); + + // Modify the CCoins for a given txid + virtual bool SetCoins(const uint256 &txid, const CCoins &coins); + + // Just check whether we have data for a given txid. + // This may (but cannot always) return true for fully spent transactions + virtual bool HaveCoins(const uint256 &txid); + + // Retrieve the block index whose state this CCoinsView currently represents + virtual CBlockIndex *GetBestBlock(); + + // Modify the currently active block index + virtual bool SetBestBlock(CBlockIndex *pindex); + + // Do a bulk modification (multiple SetCoins + one SetBestBlock) + virtual bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); + + // Calculate statistics about the unspent transaction output set + virtual bool GetStats(CCoinsStats &stats); + + // As we use CCoinsViews polymorphically, have a virtual destructor + virtual ~CCoinsView() {} +}; + +/** CCoinsView backed by another CCoinsView */ +class CCoinsViewBacked : public CCoinsView +{ +protected: + CCoinsView *base; + +public: + CCoinsViewBacked(CCoinsView &viewIn); + bool GetCoins(const uint256 &txid, CCoins &coins); + bool SetCoins(const uint256 &txid, const CCoins &coins); + bool HaveCoins(const uint256 &txid); + CBlockIndex *GetBestBlock(); + bool SetBestBlock(CBlockIndex *pindex); + void SetBackend(CCoinsView &viewIn); + bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); + bool GetStats(CCoinsStats &stats); +}; + +/** CCoinsView that adds a memory cache for transactions to another CCoinsView */ +class CCoinsViewCache : public CCoinsViewBacked +{ +protected: + CBlockIndex *pindexTip; + std::map cacheCoins; + +public: + CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); + + // Standard CCoinsView methods + bool GetCoins(const uint256 &txid, CCoins &coins); + bool SetCoins(const uint256 &txid, const CCoins &coins); + bool HaveCoins(const uint256 &txid); + CBlockIndex *GetBestBlock(); + bool SetBestBlock(CBlockIndex *pindex); + bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); + + // Return a modifiable reference to a CCoins. Check HaveCoins first. + // Many methods explicitly require a CCoinsViewCache because of this method, to reduce + // copying. + CCoins &GetCoins(const uint256 &txid); + + // Push the modifications applied to this cache to its base. + // Failure to call this method before destruction will cause the changes to be forgotten. + bool Flush(); + + // Calculate the size of the cache (in number of transactions) + unsigned int GetCacheSize(); + +private: + std::map::iterator FetchCoins(const uint256 &txid); +}; + +/** CCoinsView that brings transactions from a memorypool into view. + It does not check for spendings by memory pool transactions. */ +class CCoinsViewMemPool : public CCoinsViewBacked +{ +protected: + CTxMemPool &mempool; + +public: + CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); + bool GetCoins(const uint256 &txid, CCoins &coins); + bool HaveCoins(const uint256 &txid); +}; + +/** Global variable that points to the active CCoinsView (protected by cs_main) */ +extern CCoinsViewCache *pcoinsTip; + +/** Global variable that points to the active block tree (protected by cs_main) */ +extern CBlockTreeDB *pblocktree; + +struct CBlockTemplate +{ + CBlock block; + std::vector vTxFees; + std::vector vTxSigOps; +}; + +#if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_X64) || defined(__x86_64__) || defined(_M_AMD64) +extern unsigned int cpuid_edx; +#endif + + + + + +/** Used to relay blocks as header + vector + * to filtered nodes. + */ +class CMerkleBlock +{ +public: + // Public only for unit testing + CBlockHeader header; + CPartialMerkleTree txn; + +public: + // Public only for unit testing and relay testing + // (not relayed) + std::vector > vMatchedTxn; + + // Create from a CBlock, filtering transactions according to filter + // Note that this will call IsRelevantAndUpdate on the filter for each transaction, + // thus the filter will likely be modified. + CMerkleBlock(const CBlock& block, CBloomFilter& filter); + + IMPLEMENT_SERIALIZE + ( + READWRITE(header); + READWRITE(txn); + ) +}; + #endif diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index f01549a..974ef05 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -1,50 +1,64 @@ # Copyright (c) 2009-2010 Satoshi Nakamoto # Distributed under the MIT/X11 software license, see the accompanying -# file license.txt or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or http://www.opensource.org/licenses/mit-license.php. -DEPSDIR:=/usr/i586-mingw32msvc +DEPSDIR:=/usr/i686-w64-mingw32 + +CC := i686-w64-mingw32-gcc +CXX := i686-w64-mingw32-g++ USE_UPNP:=0 +USE_IPV6:=1 INCLUDEPATHS= \ - -I"$(DEPSDIR)/boost_1_49_0" \ - -I"$(DEPSDIR)/db-4.8.30.NC/build_unix" \ - -I"$(DEPSDIR)/openssl-1.0.1b/include" \ - -I"$(DEPSDIR)" \ + -I"$(CURDIR)" \ -I"$(CURDIR)"/obj \ + -I"$(DEPSDIR)/include" \ + -I"$(DEPSDIR)" LIBPATHS= \ - -L"$(DEPSDIR)/boost_1_49_0/stage/lib" \ - -L"$(DEPSDIR)/db-4.8.30.NC/build_unix" \ - -L"$(DEPSDIR)/openssl-1.0.1b" + -L"$(DEPSDIR)/lib" LIBS= \ + $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a \ -l boost_system-mt-s \ -l boost_filesystem-mt-s \ -l boost_program_options-mt-s \ -l boost_thread_win32-mt-s \ + -l boost_chrono-mt-s \ -l db_cxx \ -l ssl \ -l crypto -DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6 +DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE DEBUGFLAGS=-g -CFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) +xCXXFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) $(CXXFLAGS) +# enable: ASLR, DEP and large address aware +xLDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat -Wl,--large-address-aware -static-libgcc -static-libstdc++ $(LDFLAGS) TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) -ifdef USE_UPNP +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) LIBPATHS += -L"$(DEPSDIR)/miniupnpc" LIBS += -l miniupnpc -l iphlpapi DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) endif +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi # TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are HEADERS = $(wildcard *.h) OBJS= \ + leveldb/libleveldb.a \ + obj/alert.o \ obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ @@ -53,7 +67,6 @@ OBJS= \ obj/key.o \ obj/db.o \ obj/init.o \ - obj/irc.o \ obj/keystore.o \ obj/main.o \ obj/net.o \ @@ -61,6 +74,9 @@ OBJS= \ obj/bitcoinrpc.o \ obj/rpcdump.o \ obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ obj/scrypt.o \ @@ -68,31 +84,46 @@ OBJS= \ obj/util.o \ obj/wallet.o \ obj/walletdb.o \ - obj/noui.o + obj/noui.o \ + obj/hash.o \ + obj/bloom.o \ + obj/leveldb.o \ + obj/txdb.o + +ifdef USE_SSE2 +DEFS += -DUSE_SSE2 +OBJS_SSE2= obj/scrypt-sse2.o +OBJS += $(OBJS_SSE2) +endif all: casinocoind.exe -obj/scrypt.o: scrypt.c - i586-mingw32msvc-gcc -c $(CFLAGS) -o $@ $^ +DEFS += -I"$(CURDIR)/leveldb/include" +DEFS += -I"$(CURDIR)/leveldb/helpers" +leveldb/libleveldb.a: + @echo "Building LevelDB ..." && cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(xCXXFLAGS)" libleveldb.a libmemenv.a && i686-w64-mingw32-ranlib libleveldb.a && i686-w64-mingw32-ranlib libmemenv.a && cd .. obj/build.h: FORCE /bin/sh ../share/genbuild.sh obj/build.h version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO +obj/%-sse2.o: %-sse2.cpp + $(CXX) -c $(xCXXFLAGS) -msse2 -mstackrealign -o $@ $< + obj/%.o: %.cpp $(HEADERS) - i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $< + $(CXX) -c $(xCXXFLAGS) -o $@ $< casinocoind.exe: $(OBJS:obj/%=obj/%) - i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) + $(CXX) $(xCXXFLAGS) $(xLDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) obj-test/%.o: test/%.cpp $(HEADERS) - i586-mingw32msvc-g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $< + $(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -o $@ $< test_casinocoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) - i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS) + $(CXX) $(xCXXFLAGS) $(xLDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework-mt-s $(LIBS) clean: @@ -100,6 +131,7 @@ clean: -rm -f casinocoind.exe -rm -f obj-test/*.o -rm -f test_casinocoin.exe - -rm -f src/build.h + -rm -f obj/build.h + cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) clean && cd .. FORCE: diff --git a/src/makefile.mingw b/src/makefile.mingw index 0dcc260..0d468ee 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -1,48 +1,82 @@ # Copyright (c) 2009-2010 Satoshi Nakamoto # Distributed under the MIT/X11 software license, see the accompanying -# file license.txt or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or http://www.opensource.org/licenses/mit-license.php. -USE_UPNP:= +# Makefile for the MinGW g++ compiler/toolchain +# +# Assumes Berkeley DB, Boost, and OpenSSL have all been compiled and installed +# into /usr/local (/usr/local/include, /usr/local/lib). +# +# If dependencies are somewhere else, run 'make DEPSDIR=/path/' +# +# Boost libraries are given wacky names that include the particular version of +# boost you're using; set BOOST_SUFFIX appropriately. +# +# 'make clean' assumes it is running inside a MSYS shell, and uses 'rm' +# to remove files. + +CXX ?= g++ + +USE_UPNP:=- +USE_IPV6:=1 + +DEPSDIR?=/usr/local +BOOST_SUFFIX?=-mgw46-mt-s-1_53 INCLUDEPATHS= \ + -I"$(CURDIR)" \ -I"E:\crypto\deps\boost_1_53_0" \ -I"E:\crypto\deps\db-4.8.30.NC\build_unix" \ - -I"E:\crypto\deps\openssl-1.0.1b\include" + -I"E:\crypto\deps\openssl-1.0.1b\include" \ + -I"E:\crypto\deps\qrencode-3.4.3" LIBPATHS= \ + -L"$(CURDIR)/leveldb" \ -L"E:\crypto\deps\boost_1_53_0\stage\lib" \ -L"E:\crypto\deps\db-4.8.30.NC\build_unix" \ - -L"E:\crypto\deps\openssl-1.0.1b" + -L"E:\crypto\deps\openssl-1.0.1b" \ + -L"E:\crypto\deps\qrencode-3.4.3\.libs" LIBS= \ - -l boost_system-mgw46-mt-s-1_53 \ - -l boost_filesystem-mgw46-mt-s-1_53 \ - -l boost_program_options-mgw46-mt-s-1_53 \ - -l boost_thread-mgw46-mt-s-1_53 \ + -l leveldb \ + -l memenv \ + -l boost_system$(BOOST_SUFFIX) \ + -l boost_filesystem$(BOOST_SUFFIX) \ + -l boost_program_options$(BOOST_SUFFIX) \ + -l boost_thread$(BOOST_SUFFIX) \ + -l boost_chrono$(BOOST_SUFFIX) \ -l db_cxx \ -l ssl \ -l crypto -DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6 -D__NO_SYSTEM_INCLUDES - +DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6 -D__NO_SYSTEM_INCLUDES DEBUGFLAGS=-g CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) -static +# enable: ASLR, DEP and large address aware +LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat -Wl,--large-address-aware -static TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) -ifdef USE_UPNP - INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw" - LIBPATHS += -L"C:\miniupnpc-1.6-mgw" +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) LIBS += -l miniupnpc -l iphlpapi DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) endif -LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + +LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi -l pthread # TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are HEADERS = $(wildcard *.h) OBJS= \ + leveldb/libleveldb.a \ + obj/alert.o \ obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ @@ -51,7 +85,6 @@ OBJS= \ obj/key.o \ obj/db.o \ obj/init.o \ - obj/irc.o \ obj/keystore.o \ obj/main.o \ obj/net.o \ @@ -59,6 +92,9 @@ OBJS= \ obj/bitcoinrpc.o \ obj/rpcdump.o \ obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ obj/scrypt.o \ @@ -66,30 +102,53 @@ OBJS= \ obj/util.o \ obj/wallet.o \ obj/walletdb.o \ - obj/noui.o + obj/hash.o \ + obj/bloom.o \ + obj/noui.o \ + obj/leveldb.o \ + obj/txdb.o +ifdef USE_SSE2 +DEFS += -DUSE_SSE2 +OBJS_SSE2= obj/scrypt-sse2.o +OBJS += $(OBJS_SSE2) +endif all: casinocoind.exe -obj/scrypt.o: scrypt.c - gcc -c $(CFLAGS) -o $@ $^ +test check: test_casinocoin.exe FORCE + test_casinocoin.exe + +# +# LevelDB support +# +DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) +DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) + +leveldb/libleveldb.a: + cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" TARGET_OS=NATIVE_WINDOWS libleveldb.a libmemenv.a && cd .. + +obj/%-sse2.o: %-sse2.cpp + $(CXX) -c $(CFLAGS) -msse2 -mstackrealign -o $@ $< obj/%.o: %.cpp $(HEADERS) - g++ -c $(CFLAGS) -o $@ $< + $(CXX) -c $(CFLAGS) -o $@ $< casinocoind.exe: $(OBJS:obj/%=obj/%) - g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) + $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) obj-test/%.o: test/%.cpp $(HEADERS) - g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $< + $(CXX) -c $(TESTDEFS) $(CFLAGS) -o $@ $< test_casinocoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) - g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS) + $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework$(BOOST_SUFFIX) $(LIBS) clean: - -del /Q casinocoind test_casinocoin - -del /Q obj\* - -del /Q obj-test\* - -del /Q build.h + rm -f casinocoind.exe test_casinocoin.exe + rm -f obj/* + rm -f obj-test/* + cd leveldb && $(MAKE) TARGET_OS=NATIVE_WINDOWS clean && cd .. + +FORCE: diff --git a/src/makefile.osx b/src/makefile.osx index a98646d..d0fd979 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -1,9 +1,9 @@ # -*- mode: Makefile; -*- # Copyright (c) 2011 Bitcoin Developers # Distributed under the MIT/X11 software license, see the accompanying -# file license.txt or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or http://www.opensource.org/licenses/mit-license.php. -# Mac OS X makefile for casinocoin +# Mac OS X makefile for bitcoin # Originally by Laszlo Hanyecz (solar@heliacal.net) CXX=llvm-g++ @@ -20,13 +20,14 @@ LIBPATHS= \ -L"$(DEPSDIR)/lib/db48" USE_UPNP:=1 +USE_IPV6:=1 LIBS= -dead_strip TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) ifdef STATIC -# Build STATIC if you are redistributing the casinocoind binary +# Build STATIC if you are redistributing the bitcoind binary TESTLIBS += \ $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a LIBS += \ @@ -35,6 +36,7 @@ LIBS += \ $(DEPSDIR)/lib/libboost_filesystem-mt.a \ $(DEPSDIR)/lib/libboost_program_options-mt.a \ $(DEPSDIR)/lib/libboost_thread-mt.a \ + $(DEPSDIR)/lib/libboost_chrono-mt.a \ $(DEPSDIR)/lib/libssl.a \ $(DEPSDIR)/lib/libcrypto.a \ -lz @@ -47,13 +49,14 @@ LIBS += \ -lboost_filesystem-mt \ -lboost_program_options-mt \ -lboost_thread-mt \ + -lboost_chrono-mt \ -lssl \ -lcrypto \ -lz TESTDEFS += -DBOOST_TEST_DYN_LINK endif -DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6 +DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE ifdef RELEASE # Compile for maximum compatibility and smallest size. @@ -61,14 +64,19 @@ ifdef RELEASE # the same way. CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3 else -CFLAGS = -g +DEBUGFLAGS = -g endif +# osx 10.9 has changed the stdlib default to libc++. To prevent some link error, you may need to use libstdc++ +CFLAGS += -stdlib=libstdc++ + # ppc doesn't work because we don't support big-endian CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) OBJS= \ + leveldb/libleveldb.a \ + obj/alert.o \ obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ @@ -77,7 +85,6 @@ OBJS= \ obj/key.o \ obj/db.o \ obj/init.o \ - obj/irc.o \ obj/keystore.o \ obj/main.o \ obj/net.o \ @@ -85,6 +92,9 @@ OBJS= \ obj/bitcoinrpc.o \ obj/rpcdump.o \ obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ obj/scrypt.o \ @@ -92,9 +102,22 @@ OBJS= \ obj/util.o \ obj/wallet.o \ obj/walletdb.o \ - obj/noui.o + obj/hash.o \ + obj/bloom.o \ + obj/noui.o \ + obj/leveldb.o \ + obj/txdb.o -ifdef USE_UPNP +ifdef USE_SSE2 +DEFS += -DUSE_SSE2 +OBJS_SSE2= obj/scrypt-sse2.o +OBJS += $(OBJS_SSE2) +endif + +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) DEFS += -DUSE_UPNP=$(USE_UPNP) ifdef STATIC LIBS += $(DEPSDIR)/lib/libminiupnpc.a @@ -103,24 +126,40 @@ else endif endif +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + all: casinocoind +test check: test_casinocoin FORCE + ./test_casinocoin + +# +# LevelDB support +# +LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a +DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) +DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) +leveldb/libleveldb.a: + @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" libleveldb.a libmemenv.a && cd .. + # auto-generated dependencies: -include obj/*.P -include obj-test/*.P -obj/scrypt.o: scrypt.c - gcc -c $(CFLAGS) -MMD -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - rm -f $(@:%.o=%.d) - obj/build.h: FORCE /bin/sh ../share/genbuild.sh obj/build.h version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO +obj/%-sse2.o: %-sse2.cpp + $(CXX) -c $(CFLAGS) -msse2 -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + obj/%.o: %.cpp $(CXX) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ @@ -149,6 +188,7 @@ clean: -rm -f obj-test/*.o -rm -f obj/*.P -rm -f obj-test/*.P - -rm -f src/build.h + -rm -f obj/build.h + -cd leveldb && $(MAKE) clean || true FORCE: diff --git a/src/makefile.unix b/src/makefile.unix index d198692..ec65336 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -1,10 +1,19 @@ # Copyright (c) 2009-2010 Satoshi Nakamoto # Distributed under the MIT/X11 software license, see the accompanying -# file license.txt or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# :=0 --> UPnP support turned off by default at runtime +# :=1 --> UPnP support turned on by default at runtime +# :=- --> No UPnP support - miniupnp not required USE_UPNP:=0 -DEFS=-DUSE_IPV6 -DBOOST_SPIRIT_THREADSAFE +# :=1 --> Enable IPv6 support +# :=0 --> Disable IPv6 support +USE_IPV6:=1 + +LINK:=$(CXX) + +DEFS=-DBOOST_SPIRIT_THREADSAFE -D_FILE_OFFSET_BITS=64 DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) @@ -33,6 +42,10 @@ LIBS += \ -l ssl \ -l crypto +TESTLIBS += \ + -Wl,-B$(LMODE) \ + -l boost_unit_test_framework$(BOOST_LIB_SUFFIX) + ifndef USE_UPNP override USE_UPNP = - endif @@ -41,6 +54,10 @@ ifneq (${USE_UPNP}, -) DEFS += -DUSE_UPNP=$(USE_UPNP) endif +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + LIBS+= \ -Wl,-B$(LMODE2) \ -l z \ @@ -94,6 +111,8 @@ xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-para xLDFLAGS=$(LDHARDENING) $(LDFLAGS) OBJS= \ + leveldb/libleveldb.a \ + obj/alert.o \ obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ @@ -102,7 +121,6 @@ OBJS= \ obj/key.o \ obj/db.o \ obj/init.o \ - obj/irc.o \ obj/keystore.o \ obj/main.o \ obj/net.o \ @@ -110,6 +128,9 @@ OBJS= \ obj/bitcoinrpc.o \ obj/rpcdump.o \ obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ obj/scrypt.o \ @@ -117,23 +138,50 @@ OBJS= \ obj/util.o \ obj/wallet.o \ obj/walletdb.o \ - obj/noui.o + obj/hash.o \ + obj/bloom.o \ + obj/noui.o \ + obj/leveldb.o \ + obj/txdb.o +ifdef USE_SSE2 +DEFS += -DUSE_SSE2 +OBJS_SSE2= obj/scrypt-sse2.o +OBJS += $(OBJS_SSE2) +endif + all: casinocoind +test check: test_casinocoin FORCE + ./test_casinocoin + +# +# LevelDB support +# +MAKEOVERRIDES = +LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a +DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) +DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) +leveldb/libleveldb.a: + @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(xCXXFLAGS)" libleveldb.a libmemenv.a && cd .. + # auto-generated dependencies: -include obj/*.P -include obj-test/*.P -obj/scrypt.o: scrypt.c - gcc -c -o $@ $^ - obj/build.h: FORCE /bin/sh ../share/genbuild.sh obj/build.h version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO +obj/%-sse2.o: %-sse2.cpp + $(CXX) -c $(xCXXFLAGS) -msse2 -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + obj/%.o: %.cpp $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ @@ -142,7 +190,7 @@ obj/%.o: %.cpp rm -f $(@:%.o=%.d) casinocoind: $(OBJS:obj/%=obj/%) - $(CXX) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS) + $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS) TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) @@ -154,7 +202,7 @@ obj-test/%.o: test/%.cpp rm -f $(@:%.o=%.d) test_casinocoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) - $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(xLDFLAGS) $(LIBS) + $(LINK) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ $(TESTLIBS) $(xLDFLAGS) $(LIBS) clean: -rm -f casinocoind test_casinocoin @@ -162,6 +210,7 @@ clean: -rm -f obj-test/*.o -rm -f obj/*.P -rm -f obj-test/*.P - -rm -f src/build.h + -rm -f obj/build.h + -cd leveldb && $(MAKE) clean || true FORCE: diff --git a/src/mruset.h b/src/mruset.h index 5f2f00c..a527351 100644 --- a/src/mruset.h +++ b/src/mruset.h @@ -1,5 +1,4 @@ // Copyright (c) 2012 The Bitcoin developers -// Copyright (c) 2012 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_MRUSET_H diff --git a/src/net.cpp b/src/net.cpp index 157c3ce..95ab56a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,17 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "irc.h" #include "db.h" #include "net.h" #include "init.h" -#include "strlcpy.h" #include "addrman.h" #include "ui_interface.h" +#include "script.h" #ifdef WIN32 #include @@ -24,19 +21,14 @@ #include #endif +// Dump addresses to peers.dat every 15 minutes (900s) +#define DUMP_ADDRESSES_INTERVAL 900 + using namespace std; using namespace boost; static const int MAX_OUTBOUND_CONNECTIONS = 8; -void ThreadMessageHandler2(void* parg); -void ThreadSocketHandler2(void* parg); -void ThreadOpenConnections2(void* parg); -void ThreadOpenAddedConnections2(void* parg); -#ifdef USE_UPNP -void ThreadMapPort2(void* parg); -#endif -void ThreadDNSAddressSeed2(void* parg); bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); @@ -48,26 +40,25 @@ struct LocalServiceInfo { // // Global state variables // -bool fClient = false; bool fDiscover = true; -bool fUseUPnP = false; -uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); +uint64 nLocalServices = NODE_NETWORK; static CCriticalSection cs_mapLocalHost; static map mapLocalHost; static bool vfReachable[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; +static CNode* pnodeSync = NULL; uint64 nLocalHostNonce = 0; -array vnThreadsRunning; static std::vector vhListenSocket; CAddrMan addrman; +int nMaxConnections = 125; vector vNodes; CCriticalSection cs_vNodes; map mapRelay; deque > vRelayExpiration; CCriticalSection cs_mapRelay; -map mapAlreadyAskedFor; +limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static deque vOneShots; CCriticalSection cs_vOneShots; @@ -75,6 +66,9 @@ CCriticalSection cs_vOneShots; set setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses; +vector vAddedNodes; +CCriticalSection cs_vAddedNodes; + static CSemaphore *semOutbound = NULL; void AddOneShot(string strDest) @@ -157,8 +151,7 @@ bool RecvLine(SOCKET hSocket, string& strLine) } else if (nBytes <= 0) { - if (fShutdown) - return false; + boost::this_thread::interruption_point(); if (nBytes < 0) { int nErr = WSAGetLastError(); @@ -166,7 +159,7 @@ bool RecvLine(SOCKET hSocket, string& strLine) continue; if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS) { - Sleep(10); + MilliSleep(10); continue; } } @@ -235,8 +228,8 @@ bool AddLocal(const CService& addr, int nScore) bool fAlready = mapLocalHost.count(addr) > 0; LocalServiceInfo &info = mapLocalHost[addr]; if (!fAlready || nScore >= info.nScore) { - info.nScore = nScore; - info.nPort = addr.GetPort() + (fAlready ? 1 : 0); + info.nScore = nScore + (fAlready ? 1 : 0); + info.nPort = addr.GetPort(); } SetReachable(addr.GetNetwork()); } @@ -347,7 +340,6 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha return error("GetMyExternalIP() : connection closed"); } -// We now get our external IP from the IRC server first and only use this as a backup bool GetMyExternalIP(CNetAddr& ipRet) { CService addrConnect; @@ -357,13 +349,13 @@ bool GetMyExternalIP(CNetAddr& ipRet) for (int nLookup = 0; nLookup <= 1; nLookup++) for (int nHost = 1; nHost <= 2; nHost++) { - // We should be phasing out our use of sites like these. If we need + // We should be phasing out our use of sites like these. If we need // replacements, we should ask for volunteers to put this simple - // php file on their webserver that prints the client IP: + // php file on their web server that prints the client IP: // if (nHost == 1) { - addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org + addrConnect = CService("91.198.22.70", 80); // checkip.dyndns.org if (nLookup == 1) { @@ -437,12 +429,10 @@ void AddressCurrentlyConnected(const CService& addr) CNode* FindNode(const CNetAddr& ip) { - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if ((CNetAddr)pnode->addr == ip) - return (pnode); - } + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if ((CNetAddr)pnode->addr == ip) + return (pnode); return NULL; } @@ -457,16 +447,14 @@ CNode* FindNode(std::string addrName) CNode* FindNode(const CService& addr) { - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if ((CService)pnode->addr == addr) - return (pnode); - } + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if ((CService)pnode->addr == addr) + return (pnode); return NULL; } -CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout) +CNode* ConnectNode(CAddress addrConnect, const char *pszDest) { if (pszDest == NULL) { if (IsLocal(addrConnect)) @@ -476,10 +464,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout) CNode* pnode = FindNode((CService)addrConnect); if (pnode) { - if (nTimeout != 0) - pnode->AddRef(nTimeout); - else - pnode->AddRef(); + pnode->AddRef(); return pnode; } } @@ -499,22 +484,19 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout) /// debug print printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str()); - // Set to nonblocking + // Set to non-blocking #ifdef WIN32 u_long nOne = 1; if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) - printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError()); + printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); #else if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) - printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno); + printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); #endif // Add node CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); - if (nTimeout != 0) - pnode->AddRef(nTimeout); - else - pnode->AddRef(); + pnode->AddRef(); { LOCK(cs_vNodes); @@ -538,8 +520,16 @@ void CNode::CloseSocketDisconnect() printf("disconnecting node %s\n", addrName.c_str()); closesocket(hSocket); hSocket = INVALID_SOCKET; - vRecv.clear(); } + + // in case this fails, we'll empty the recv buffer when the CNode is deleted + TRY_LOCK(cs_vRecvMsg, lockRecv); + if (lockRecv) + vRecvMsg.clear(); + + // if this was the sync node, we'll need a new one + if (this == pnodeSync) + pnodeSync = NULL; } void CNode::Cleanup() @@ -591,7 +581,7 @@ bool CNode::Misbehaving(int howmuch) { if (addr.IsLocal()) { - printf("Warning: local node %s misbehaving\n", addrName.c_str()); + printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch); return false; } @@ -599,15 +589,16 @@ bool CNode::Misbehaving(int howmuch) if (nMisbehavior >= GetArg("-banscore", 100)) { int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban + printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); { LOCK(cs_setBanned); if (setBanned[addr] < banTime) setBanned[addr] = banTime; } CloseSocketDisconnect(); - printf("Disconnected %s for misbehavior (score=%d)\n", addrName.c_str(), nMisbehavior); return true; - } + } else + printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); return false; } @@ -621,52 +612,145 @@ void CNode::copyStats(CNodeStats &stats) X(nTimeConnected); X(addrName); X(nVersion); - X(strSubVer); + X(cleanSubVer); X(fInbound); - X(nReleaseTime); X(nStartingHeight); X(nMisbehavior); + X(nSendBytes); + X(nRecvBytes); + X(nBlocksRequested); + stats.fSyncNode = (this == pnodeSync); } #undef X - - - - - - - - - -void ThreadSocketHandler(void* parg) +// requires LOCK(cs_vRecvMsg) +bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) { - IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg)); + while (nBytes > 0) { - // Make this thread recognisable as the networking thread - RenameThread("bitcoin-net"); + // get current incomplete message, or create a new one + if (vRecvMsg.empty() || + vRecvMsg.back().complete()) + vRecvMsg.push_back(CNetMessage(SER_NETWORK, nRecvVersion)); - try - { - vnThreadsRunning[THREAD_SOCKETHANDLER]++; - ThreadSocketHandler2(parg); - vnThreadsRunning[THREAD_SOCKETHANDLER]--; + CNetMessage& msg = vRecvMsg.back(); + + // absorb network data + int handled; + if (!msg.in_data) + handled = msg.readHeader(pch, nBytes); + else + handled = msg.readData(pch, nBytes); + + if (handled < 0) + return false; + + pch += handled; + nBytes -= handled; } - catch (std::exception& e) { - vnThreadsRunning[THREAD_SOCKETHANDLER]--; - PrintException(&e, "ThreadSocketHandler()"); - } catch (...) { - vnThreadsRunning[THREAD_SOCKETHANDLER]--; - throw; // support pthread_cancel() - } - printf("ThreadSocketHandler exited\n"); + + return true; } -void ThreadSocketHandler2(void* parg) +int CNetMessage::readHeader(const char *pch, unsigned int nBytes) { - printf("ThreadSocketHandler started\n"); - list vNodesDisconnected; - unsigned int nPrevNodeCount = 0; + // copy data to temporary parsing buffer + unsigned int nRemaining = 24 - nHdrPos; + unsigned int nCopy = std::min(nRemaining, nBytes); + memcpy(&hdrbuf[nHdrPos], pch, nCopy); + nHdrPos += nCopy; + + // if header incomplete, exit + if (nHdrPos < 24) + return nCopy; + + // deserialize to CMessageHeader + try { + hdrbuf >> hdr; + } + catch (std::exception &e) { + return -1; + } + + // reject messages larger than MAX_SIZE + if (hdr.nMessageSize > MAX_SIZE) + return -1; + + // switch state to reading message data + in_data = true; + vRecv.resize(hdr.nMessageSize); + + return nCopy; +} + +int CNetMessage::readData(const char *pch, unsigned int nBytes) +{ + unsigned int nRemaining = hdr.nMessageSize - nDataPos; + unsigned int nCopy = std::min(nRemaining, nBytes); + + memcpy(&vRecv[nDataPos], pch, nCopy); + nDataPos += nCopy; + + return nCopy; +} + + + + + + + + + +// requires LOCK(cs_vSend) +void SocketSendData(CNode *pnode) +{ + std::deque::iterator it = pnode->vSendMsg.begin(); + + while (it != pnode->vSendMsg.end()) { + const CSerializeData &data = *it; + assert(data.size() > pnode->nSendOffset); + int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); + if (nBytes > 0) { + pnode->nLastSend = GetTime(); + pnode->nSendBytes += nBytes; + pnode->nSendOffset += nBytes; + if (pnode->nSendOffset == data.size()) { + pnode->nSendOffset = 0; + pnode->nSendSize -= data.size(); + it++; + } else { + // could not send full message; stop sending more + break; + } + } else { + if (nBytes < 0) { + // error + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + { + printf("socket send error %d\n", nErr); + pnode->CloseSocketDisconnect(); + } + } + // couldn't send anything at all + break; + } + } + + if (it == pnode->vSendMsg.end()) { + assert(pnode->nSendOffset == 0); + assert(pnode->nSendSize == 0); + } + pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); +} + +static list vNodesDisconnected; + +void ThreadSocketHandler() +{ + unsigned int nPrevNodeCount = 0; loop { // @@ -679,7 +763,7 @@ void ThreadSocketHandler2(void* parg) BOOST_FOREACH(CNode* pnode, vNodesCopy) { if (pnode->fDisconnect || - (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty())) + (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty())) { // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); @@ -692,7 +776,6 @@ void ThreadSocketHandler2(void* parg) pnode->Cleanup(); // hold in disconnected pool until all refs are released - pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60); if (pnode->fNetworkNode || pnode->fInbound) pnode->Release(); vNodesDisconnected.push_back(pnode); @@ -711,16 +794,12 @@ void ThreadSocketHandler2(void* parg) TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { - TRY_LOCK(pnode->cs_vRecv, lockRecv); + TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - TRY_LOCK(pnode->cs_mapRequests, lockReq); - if (lockReq) - { - TRY_LOCK(pnode->cs_inventory, lockInv); - if (lockInv) - fDelete = true; - } + TRY_LOCK(pnode->cs_inventory, lockInv); + if (lockInv) + fDelete = true; } } } @@ -753,10 +832,12 @@ void ThreadSocketHandler2(void* parg) FD_ZERO(&fdsetSend); FD_ZERO(&fdsetError); SOCKET hSocketMax = 0; + bool have_fds = false; BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) { FD_SET(hListenSocket, &fdsetRecv); hSocketMax = max(hSocketMax, hListenSocket); + have_fds = true; } { LOCK(cs_vNodes); @@ -764,34 +845,58 @@ void ThreadSocketHandler2(void* parg) { if (pnode->hSocket == INVALID_SOCKET) continue; - FD_SET(pnode->hSocket, &fdsetRecv); FD_SET(pnode->hSocket, &fdsetError); hSocketMax = 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). { TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend && !pnode->vSend.empty()) + if (lockSend && !pnode->vSendMsg.empty()) { FD_SET(pnode->hSocket, &fdsetSend); + continue; + } + } + { + TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); + if (lockRecv && ( + pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || + pnode->GetTotalRecvSize() <= ReceiveFloodSize())) + FD_SET(pnode->hSocket, &fdsetRecv); } } } - vnThreadsRunning[THREAD_SOCKETHANDLER]--; - int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); - vnThreadsRunning[THREAD_SOCKETHANDLER]++; - if (fShutdown) - return; + int nSelect = select(have_fds ? hSocketMax + 1 : 0, + &fdsetRecv, &fdsetSend, &fdsetError, &timeout); + boost::this_thread::interruption_point(); + if (nSelect == SOCKET_ERROR) { - int nErr = WSAGetLastError(); - if (hSocketMax != INVALID_SOCKET) + if (have_fds) { + int nErr = WSAGetLastError(); printf("socket select error %d\n", nErr); for (unsigned int i = 0; i <= hSocketMax; i++) FD_SET(i, &fdsetRecv); } FD_ZERO(&fdsetSend); FD_ZERO(&fdsetError); - Sleep(timeout.tv_usec/1000); + MilliSleep(timeout.tv_usec/1000); } @@ -813,7 +918,7 @@ void ThreadSocketHandler2(void* parg) if (hSocket != INVALID_SOCKET) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) - printf("warning: unknown socket family\n"); + printf("Warning: Unknown socket family\n"); { LOCK(cs_vNodes); @@ -824,10 +929,11 @@ void ThreadSocketHandler2(void* parg) if (hSocket == INVALID_SOCKET) { - if (WSAGetLastError() != WSAEWOULDBLOCK) - printf("socket error accept failed: %d\n", WSAGetLastError()); + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK) + printf("socket error accept failed: %d\n", nErr); } - else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) + else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) { { LOCK(cs_setservAddNodeAddresses); @@ -865,8 +971,7 @@ void ThreadSocketHandler2(void* parg) } BOOST_FOREACH(CNode* pnode, vNodesCopy) { - if (fShutdown) - return; + boost::this_thread::interruption_point(); // // Receive @@ -875,26 +980,19 @@ void ThreadSocketHandler2(void* parg) continue; if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) { - TRY_LOCK(pnode->cs_vRecv, lockRecv); + TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - CDataStream& vRecv = pnode->vRecv; - unsigned int nPos = vRecv.size(); - - if (nPos > ReceiveBufferSize()) { - if (!pnode->fDisconnect) - printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size()); - pnode->CloseSocketDisconnect(); - } - else { + { // typical socket buffer is 8K-64K char pchBuf[0x10000]; int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); if (nBytes > 0) { - vRecv.resize(nPos + nBytes); - memcpy(&vRecv[nPos], pchBuf, nBytes); + if (!pnode->ReceiveMsgBytes(pchBuf, nBytes)) + pnode->CloseSocketDisconnect(); pnode->nLastRecv = GetTime(); + pnode->nRecvBytes += nBytes; } else if (nBytes == 0) { @@ -927,34 +1025,13 @@ void ThreadSocketHandler2(void* parg) { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - { - CDataStream& vSend = pnode->vSend; - if (!vSend.empty()) - { - int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT); - if (nBytes > 0) - { - vSend.erase(vSend.begin(), vSend.begin() + nBytes); - pnode->nLastSend = GetTime(); - } - else if (nBytes < 0) - { - // error - int nErr = WSAGetLastError(); - if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) - { - printf("socket send error %d\n", nErr); - pnode->CloseSocketDisconnect(); - } - } - } - } + SocketSendData(pnode); } // // Inactivity checking // - if (pnode->vSend.empty()) + if (pnode->vSendMsg.empty()) pnode->nLastSendEmpty = GetTime(); if (GetTime() - pnode->nTimeConnected > 60) { @@ -981,7 +1058,7 @@ void ThreadSocketHandler2(void* parg) pnode->Release(); } - Sleep(10); + MilliSleep(10); } } @@ -994,36 +1071,9 @@ void ThreadSocketHandler2(void* parg) #ifdef USE_UPNP -void ThreadMapPort(void* parg) +void ThreadMapPort() { - IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg)); - - // Make this thread recognisable as the UPnP thread - RenameThread("bitcoin-UPnP"); - - try - { - vnThreadsRunning[THREAD_UPNP]++; - ThreadMapPort2(parg); - vnThreadsRunning[THREAD_UPNP]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_UPNP]--; - PrintException(&e, "ThreadMapPort()"); - } catch (...) { - vnThreadsRunning[THREAD_UPNP]--; - PrintException(NULL, "ThreadMapPort()"); - } - printf("ThreadMapPort exited\n"); -} - -void ThreadMapPort2(void* parg) -{ - printf("ThreadMapPort started\n"); - - char port[6]; - sprintf(port, "%d", GetListenPort()); - + std::string port = strprintf("%u", GetListenPort()); const char * multicastif = 0; const char * minissdpdpath = 0; struct UPNPDev * devlist = 0; @@ -1063,88 +1113,89 @@ void ThreadMapPort2(void* parg) } string strDesc = "CasinoCoin " + FormatFullVersion(); -#ifndef UPNPDISCOVER_SUCCESS - /* miniupnpc 1.5 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0); -#else - /* miniupnpc 1.6 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); -#endif - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port, port, lanaddr, r, strupnperror(r)); - else - printf("UPnP Port Mapping successful.\n"); - int i = 1; - loop { - if (fShutdown || !fUseUPnP) - { - r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, "TCP", 0); - printf("UPNP_DeletePortMapping() returned : %d\n", r); - freeUPNPDevlist(devlist); devlist = 0; - FreeUPNPUrls(&urls); - return; - } - if (i % 600 == 0) // Refresh every 20 minutes - { + try { + loop { #ifndef UPNPDISCOVER_SUCCESS /* miniupnpc 1.5 */ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0); + port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); #else /* miniupnpc 1.6 */ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); + port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); #endif if(r!=UPNPCOMMAND_SUCCESS) printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port, port, lanaddr, r, strupnperror(r)); + port.c_str(), port.c_str(), lanaddr, r, strupnperror(r)); else printf("UPnP Port Mapping successful.\n");; + + MilliSleep(20*60*1000); // Refresh every 20 minutes } - Sleep(2000); - i++; + } + catch (boost::thread_interrupted) + { + r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); + printf("UPNP_DeletePortMapping() returned : %d\n", r); + freeUPNPDevlist(devlist); devlist = 0; + FreeUPNPUrls(&urls); + throw; } } else { printf("No valid UPnP IGDs found\n"); freeUPNPDevlist(devlist); devlist = 0; if (r != 0) FreeUPNPUrls(&urls); - loop { - if (fShutdown || !fUseUPnP) - return; - Sleep(2000); - } } } -void MapPort() +void MapPort(bool fUseUPnP) { - if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1) + static boost::thread* upnp_thread = NULL; + + if (fUseUPnP) { - if (!CreateThread(ThreadMapPort, NULL)) - printf("Error: ThreadMapPort(ThreadMapPort) failed\n"); + if (upnp_thread) { + upnp_thread->interrupt(); + upnp_thread->join(); + delete upnp_thread; + } + upnp_thread = new boost::thread(boost::bind(&TraceThread >, "upnp", &ThreadMapPort)); + } + else if (upnp_thread) { + upnp_thread->interrupt(); + upnp_thread->join(); + delete upnp_thread; + upnp_thread = NULL; } } + #else -void MapPort() +void MapPort(bool) { // Intentionally left blank. } #endif + + + + + + + + // DNS seeds // Each pair gives a source name and a seed name. // The first name is used as information source for addrman. // The second name should resolve to a list of seed addresses. static const char *strMainNetDNSSeed[][2] = { - {"casinoco.in seed #1", "seed1.casinoco.in"}, - {"casinoco.in seed #2", "seed2.casinoco.in"}, - {"casinoco.in seed", "seed.casinoco.in"}, + {"casinoco.in seed", "seed.casinoco.in"}, + {"casinoco.in seed #1", "seed1.casinoco.in"}, + {"casinoco.in seed #2", "seed2.casinoco.in"}, + {"casinoco.in seed #3", "seed3.casinoco.in"}, {NULL, NULL} }; @@ -1153,138 +1204,53 @@ static const char *strTestNetDNSSeed[][2] = { {NULL, NULL} }; -void ThreadDNSAddressSeed(void* parg) +void ThreadDNSAddressSeed() { - IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); + static const char *(*strDNSSeed)[2] = fTestNet ? strTestNetDNSSeed : strMainNetDNSSeed; - // Make this thread recognisable as the DNS seeding thread - RenameThread("bitcoin-dnsseed"); - - try - { - vnThreadsRunning[THREAD_DNSSEED]++; - ThreadDNSAddressSeed2(parg); - vnThreadsRunning[THREAD_DNSSEED]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_DNSSEED]--; - PrintException(&e, "ThreadDNSAddressSeed()"); - } catch (...) { - vnThreadsRunning[THREAD_DNSSEED]--; - throw; // support pthread_cancel() - } - printf("ThreadDNSAddressSeed exited\n"); -} - -void ThreadDNSAddressSeed2(void* parg) -{ - printf("ThreadDNSAddressSeed started\n"); int found = 0; - if (true) // minimize diff, this is the last version of 0.6.x - { - printf("Loading addresses from DNS seeds (could take a while)\n"); + printf("Loading addresses from DNS seeds (could take a while)\n"); - static const char *(*strDNSSeed)[2] = fTestNet ? strTestNetDNSSeed : strMainNetDNSSeed; - - for (unsigned int seed_idx = 0; strDNSSeed[seed_idx][0] != NULL; seed_idx++) { - if (GetNameProxy()) { - AddOneShot(strDNSSeed[seed_idx][1]); - } else { - vector vaddr; - vector vAdd; - if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) + for (unsigned int seed_idx = 0; strDNSSeed[seed_idx][0] != NULL; seed_idx++) { + if (HaveNameProxy()) { + AddOneShot(strDNSSeed[seed_idx][1]); + } else { + vector vaddr; + vector vAdd; + if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) + { + BOOST_FOREACH(CNetAddr& ip, vaddr) { - BOOST_FOREACH(CNetAddr& ip, vaddr) - { - int nOneDay = 24*3600; - CAddress addr = CAddress(CService(ip, GetDefaultPort())); - addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old - vAdd.push_back(addr); - found++; - } + int nOneDay = 24*3600; + CAddress addr = CAddress(CService(ip, GetDefaultPort())); + addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old + vAdd.push_back(addr); + found++; } - addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true)); } + addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true)); } } printf("%d addresses found from DNS seeds\n", found); } + + + + + + + + + + + unsigned int pnSeed[] = { - 0xdfae795b, 0x0e0f46a6, 0xaf7f170c, 0x900486bc, 0xcbac226c, 0x3b551ac7, 0x56eb5d50, 0x136f21b2, - 0x8ddd57d0, 0xb291f363, 0xe57a3c47, 0x66c52560, 0x22b49640, 0xc76aaa1f, 0x5a90693e, 0x3534bdd5, - 0x37a06044, 0x43ecf65b, 0x4ce4995b, 0x7a563c43, 0x29d80c47, 0xe995316c, 0x1aeb864a, 0x3efc3d2a, - 0xf0e2a447, 0xaab216d2, 0xe74daa46, 0xa55fdcac, 0x2b8c811f, 0x625ec650, 0x2876a565, 0xfed55d50, - 0x9673bb48, 0xcd50d74a, 0xc048ed5e, 0xfe56ea47, 0x7e91a562, 0x6c6a888e, 0x07d55753, 0x8bb0bf42, - 0xf61bfd53, 0x1c26ea47, 0x849965ae, 0x96045d47, 0x0a4605be, 0x1f6a2a60, 0x8229fd18, 0x21cd11b8, - 0x9ea641ad, 0xad49d543, 0x45a6814a, 0x77ded690, 0x2dea1b52, 0xef73ad55, 0x8cc5614c, 0x43aca146, - 0x04c89851, 0xb130cb50, 0x686ff23c, 0x369a5f4b, 0x3cb58705, 0x54cd844b, 0x370d854f, 0xea812942, - 0xbc452864, 0xcef02a60, 0x6df6f854, 0xb5666251, 0x2d49386c, 0xb3892660, 0x7551f950, 0x0808a496, - 0x848954c6, 0x16f91ead, 0xd8d3834b, 0x7383794c, 0x8c68fc18, 0x7088066c, 0x5147b445, 0x87c052d8, - 0x4ab15cd4, 0xb8d53b44, 0xe5aa194c, 0x38bc6844, 0x5454c854, 0xfd091718, 0x7107a86c, 0x6454c854, - 0xc4bc8832, 0xfc67dcad, 0x091cb2c6, 0xada7ef47, 0xfcb3c05e, 0x0904f560, 0x37485253, 0x58aef763, - 0xfe716044, 0x1347eb63, 0xad435946, 0xb629d459, 0xf1785851, 0x6f3ec34a, 0xee079e4e, 0x515b7c46, - 0x1be31e98, 0x69f2e862, 0xd2d16f62, 0xb8cc9662, 0x340ad8b4, 0xdb15ee54, 0xaa81af51, 0xdfc57046, - 0xa44fbd42, 0x64f90456, 0x030dc65a, 0xd9842660, 0x03b6da18, 0x64786d4a, 0x8c8f338f, 0x0ec07acb, - 0xb4a5b34f, 0x3c815032, 0x330c1c71, 0x2abe814a, 0xdf0d62ae, 0x33e64979, 0x634dae58, 0xb14d40ad, - 0x948afe45, 0xf8545e4a, 0x9289f37b, 0x2c28a565, 0x25498232, 0x2dabed62, 0xb54df37b, 0x424a7d4c, - 0x1570456c, 0x0cf6bf42, 0x6e4a3f44, 0xa87158c3, 0x6910fb47, 0x29b8a247, 0xcb8d1518, 0x1d326596, - 0x3636dd50, 0xf9e5d762, 0x59d09a5e, 0x41a63e47, 0x5200a6b8, 0x38b71318, 0xc0c3456f, 0x02c6a43c, - 0xc92909b0, 0xa6b913d8, 0xe8b4e462, 0x6e30ac4c, 0x64439ca8, 0xdf8c5a18, 0xc24751d5, 0x5dc9fc6c, - 0xa9a15861, 0x87c4a73b, 0x243441ad, 0x2a853c42, 0x0188339a, 0xf3570f18, 0x0be83d44, 0xffa97257, - 0x23e026d0, 0x86b43760, 0x35ab664c, 0x22740f48, 0x6b6d4318, 0x9a1b1bd8, 0x12d0b64f, 0xd388b23e, - 0xd75cfddc, 0x8780cc47, 0x780e0e45, 0x2251cc82, 0x19fe8418, 0xefa5602a, 0xfb5f1074, 0xdc26ccc7, - 0xad5e7e4c, 0xb271922e, 0xb7054242, 0x9b9d7b47, 0xf9d4d862, 0x0de6e6d8, 0xf3dbcd48, 0x677fc3cc, - 0x7e6e1552, 0x40d69a18, 0x4cb1e152, 0xb4278c18, 0xa5be002e, 0xa95aac43, 0x6587454b, 0x513de262, - 0x15505a4e, 0x92434f46, 0x56522d79, 0x8453c918, 0x821b7544, 0xea69df50, 0xc7da4f5f, 0xcd12dc55, - 0x598a9147, 0x65ef7262, 0xdc454f46, 0x2119bc2e, 0xbedc7eae, 0x6ca8f536, 0x4497eb18, 0xe7ef80c3, - 0xd9a48e4b, 0x52946dcb, 0xcff428b2, 0x2eca1018, 0x4a685747, 0x77967045, 0x68801132, 0x9149ca62, - 0x04cc0844, 0xd65745b8, 0x4fb08218, 0x31362041, 0xa56c1d46, 0x89af1e47, 0x2d3fdb47, 0x1a3c146c, - 0xda1a694a, 0xf534c848, 0x8eee1eb7, 0xb7aac547, 0x1324f450, 0xaa88f745, 0x77e4aa8d, 0x8a1d52b8, - 0xb2499044, 0x26cb1918, 0x926d5c41, 0x4c218a4b, 0x27a90a4c, 0x1cbc8b59, 0x24ff7d4c, 0x391cc36d, - 0x0b58fddc, 0xc3ac0844, 0xe9d90ad8, 0x1b2f412e, 0x6a221b60, 0xe3518048, 0xc4071975, 0x1c3f72d8, - 0x1e8822d9, 0x067c7a76, 0x557cd782, 0xd5df0e43, 0x831a19bc, 0xe270ac55, 0x2106be5f, 0x49130087, - 0xdd1f0164, 0x76c75753, 0x2e935d02, 0x5491f460, 0x05736344, 0x748c3bda, 0x9534e95c, 0x64e9e444, - 0x96d55d61, 0xd9421656, 0xb044a143, 0xd2ca5a61, 0xbe074854, 0x48dadd43, 0x9cf29b18, 0x4641ee5c, - 0xa2581b53, 0xd585b86c, 0xa77c8a55, 0x5bd5aa47, 0x3b1a3947, 0x4cbcda51, 0x881a94b2, 0x463dc058, - 0xdc241618, 0x9f3b5d47, 0xdd431b4c, 0x76c9db57, 0x2dbfae47, 0x71a8fb53, 0x5447d562, 0x27f1e44e, - 0x0d7aa76c, 0x3e714945, 0x3fa9c544, 0xa6683532, 0x96e0fa45, 0xc4f8d782, 0xd6bddf62, 0xa1536d54, - 0x9404aa56, 0xca7bd742, 0x5ebc0164, 0x37737f45, 0x0fb8d2cc, 0x8dd4c04a, 0xdef43160, 0x71ff5053, - 0xbfe55d5f, 0x3539b34c, 0x90cdbeb8, 0xdb4e2247, 0x3bcc0b1f, 0xce5e5144, 0x7d7f57c7, 0xeeef3d55, - 0xea4a7752, 0x4a1906ae, 0x21e1cc6c, 0xe5b21cad, 0x10ab554b, 0xf553b147, 0xb796d162, 0x0aff2744, - 0x6b657054, 0x9115a665, 0xd873fb4d, 0x5abcd418, 0xccaf8ad5, 0x8dfb0718, 0x3bd6c248, 0xa581614c, - 0x18516041, 0xfa8c8e32, 0x96d33ea8, 0x0fed615f, 0x7b34c9dd, 0x928fa944, 0xb598b0ba, 0x9de9d562, - 0xa9c3bd4b, 0x5c275cae, 0xd61a8945, 0xcdc47f60, 0x0a46e962, 0x6596ed18, 0xae7ac46b, 0x5bcc4748, - 0x9ad6ba18, 0x1c428d4b, 0x9d0efa59, 0x68c006d1, 0xaedf5f41, 0x7caf0918, 0x48519b32, 0x091d1d46, - 0x36c0d176, 0xdb5be248, 0xc21d3b46, 0x18c61418, 0xd5a26044, 0x05898d18, 0xf11ee3be, 0xd10340ad, - 0xea33e218, 0xc4f3b742, 0xe5a50f18, 0x46f63b4a, 0xff72341f, 0x7c901dad, 0xc74f1162, 0xdf2b5032, - 0xc29b296c, 0x3c8eec5c, 0xfa8eaf6e, 0xc0bb5475, 0x4d2e1a46, 0x31f55a42, 0xa4fd211b, 0x8eed4147, - 0x506a3f18, 0x28521856, 0x88ccec47, 0xa8a92160, 0x4aa70e18, 0x1e644442, 0xc657ddd8, 0x368ce663, - 0xbe9859d1, 0x3e245ad4, 0xe6029744, 0x31de1f52, 0x4c617544, 0x945830ae, 0x5f82b543, 0xccfa574b, - 0xdee3b944, 0xb80bfcd8, 0x80b85741, 0x0980a545, 0x1c8dac62, 0x82ba6e62, 0x03c6ea42, 0x74c53b44, - 0xf9e02ebd, 0xcc3f715b, 0x942b0145, 0x9c8da545, 0x31980925, 0xcb9dd562, 0xf0ba0e4c, 0x9208564e, - 0x8ba74055, 0x96ed6c4b, 0x4057d74a, 0xc8d569d8, 0xfd48e4a5, 0x2f695670, 0x8387d418, 0x0902dd5f, - 0xf15aef47, 0x4368c65a, 0x2aeea988, 0xbdf6a94c, 0x7136165f, 0x86ea3dae, 0x8bbd1c6c, 0x9d2ed447, - 0x1987b59e, 0xc2bbb74f, 0x34b70b5c, 0xfaf65741, 0xab46e763, 0x33d454c6, 0xc26df645, 0x5f7351cf, - 0xf2ebefdc, 0xd4165c61, 0xafada73b, 0x68eaf7de, 0x0cee73d4, 0xc1753532, 0xda64f555, 0x6144406d, - 0x5eb0fb6c, 0x8993c90e, 0xab6d8792, 0x06d8a95f, 0xc60cfe45, 0xe3efb948, 0x0a393744, 0x8f47bcce, - 0x44b7d4b0, 0x3080fb4d, 0x2b95e744, 0xb010324d, 0xf820e247, 0x47384b80, 0xa54c41bc, 0x63a07618, - 0x004c4f5f, 0xde9aca47, 0xf9a842b8, 0x7208ae4b, 0x59927257, 0x2d1ea27c, 0x0386c65e, 0x3d0b6b3a, - 0x4ce6bd4b, 0x49ca67d5, 0xe1333bcb, 0x97684f5f, 0x54d130ad, 0x62470b25, 0xc11acab2, 0x6e7f947a, - 0x93f08056, 0x40588256, 0xf069e048, 0x4d224952, 0xcb846250, 0x4c9eaf6e, 0x7a2efe53, 0xa67ac3d1, - 0x64e3604a, 0xb5e154b2, 0x622a941f, 0xea76ca5c, 0x63f0515d, 0xe63efe62, 0x2ccbda72, 0x1c262b44, - 0x336fd956, 0x9d9f687a, 0x85d88856, 0xfc77be2e, 0x1c41bb7c, 0xf29c554d, 0x1268ee50, 0xd82d1abc, - 0x037a083a, 0xca5c8240, 0xf76fa73b, 0x2589494d, 0x3499fe4d, 0x67005553, 0xef8295b6, 0x21ca9662, - 0x4f8f1532, 0x480541b2, 0x0311d779, 0xb8b9a73b, 0xdb570a70, 0x93542dba, 0xde05a765, 0x23e863b0, - 0x69590352, 0xc8df0d56, 0x7e44db5d, 0x626aa97c, 0xf08b904f, 0x8be7063a, 0x288da94f, 0x7c9d1a41, - 0xae369478, 0xb1376c7a, 0x2b66cf18, 0xb021cf18, 0xafad957a, 0x8b69d62e, 0x32d3a87c, 0xc4ad846d, - 0x04c9888d, 0x418a3c02, 0x4f680471, 0x5881bd5e, 0x80bf0b1f, 0x569f966d, 0xae28fb5c, 0x25816c4a }; - void DumpAddresses() { int64 nStart = GetTimeMillis(); @@ -1296,59 +1262,6 @@ void DumpAddresses() addrman.size(), GetTimeMillis() - nStart); } -void ThreadDumpAddress2(void* parg) -{ - vnThreadsRunning[THREAD_DUMPADDRESS]++; - while (!fShutdown) - { - DumpAddresses(); - vnThreadsRunning[THREAD_DUMPADDRESS]--; - Sleep(100000); - vnThreadsRunning[THREAD_DUMPADDRESS]++; - } - vnThreadsRunning[THREAD_DUMPADDRESS]--; -} - -void ThreadDumpAddress(void* parg) -{ - IMPLEMENT_RANDOMIZE_STACK(ThreadDumpAddress(parg)); - - // Make this thread recognisable as the address dumping thread - RenameThread("bitcoin-adrdump"); - - try - { - ThreadDumpAddress2(parg); - } - catch (std::exception& e) { - PrintException(&e, "ThreadDumpAddress()"); - } - printf("ThreadDumpAddress exited\n"); -} - -void ThreadOpenConnections(void* parg) -{ - IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg)); - - // Make this thread recognisable as the connection opening thread - RenameThread("bitcoin-opencon"); - - try - { - vnThreadsRunning[THREAD_OPENCONNECTIONS]++; - ThreadOpenConnections2(parg); - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - PrintException(&e, "ThreadOpenConnections()"); - } catch (...) { - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - PrintException(NULL, "ThreadOpenConnections()"); - } - printf("ThreadOpenConnections exited\n"); -} - void static ProcessOneShot() { string strDest; @@ -1367,12 +1280,10 @@ void static ProcessOneShot() } } -void ThreadOpenConnections2(void* parg) +void ThreadOpenConnections() { - printf("ThreadOpenConnections started\n"); - // Connect to specific addresses - if (mapArgs.count("-connect")) + if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { for (int64 nLoop = 0;; nLoop++) { @@ -1383,11 +1294,10 @@ void ThreadOpenConnections2(void* parg) OpenNetworkConnection(addr, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { - Sleep(500); - if (fShutdown) - return; + MilliSleep(500); } } + MilliSleep(500); } } @@ -1397,18 +1307,10 @@ void ThreadOpenConnections2(void* parg) { ProcessOneShot(); - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - Sleep(500); - vnThreadsRunning[THREAD_OPENCONNECTIONS]++; - if (fShutdown) - return; + MilliSleep(500); - - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; CSemaphoreGrant grant(*semOutbound); - vnThreadsRunning[THREAD_OPENCONNECTIONS]++; - if (fShutdown) - return; + boost::this_thread::interruption_point(); // Add seed nodes if IRC isn't working if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet) @@ -1461,7 +1363,12 @@ void ThreadOpenConnections2(void* parg) if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) break; + // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, + // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates + // already-connected network ranges, ...) before trying new addrman addresses. nTries++; + if (nTries > 100) + break; if (IsLimited(addr)) continue; @@ -1483,108 +1390,85 @@ void ThreadOpenConnections2(void* parg) } } -void ThreadOpenAddedConnections(void* parg) +void ThreadOpenAddedConnections() { - IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg)); - - // Make this thread recognisable as the connection opening thread - RenameThread("bitcoin-opencon"); - - try { - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; - ThreadOpenAddedConnections2(parg); - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + LOCK(cs_vAddedNodes); + vAddedNodes = mapMultiArgs["-addnode"]; } - catch (std::exception& e) { - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; - PrintException(&e, "ThreadOpenAddedConnections()"); - } catch (...) { - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; - PrintException(NULL, "ThreadOpenAddedConnections()"); - } - printf("ThreadOpenAddedConnections exited\n"); -} -void ThreadOpenAddedConnections2(void* parg) -{ - printf("ThreadOpenAddedConnections started\n"); - - if (mapArgs.count("-addnode") == 0) - return; - - if (GetNameProxy()) { - while(!fShutdown) { - BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) { + if (HaveNameProxy()) { + while(true) { + list lAddresses(0); + { + LOCK(cs_vAddedNodes); + BOOST_FOREACH(string& strAddNode, vAddedNodes) + lAddresses.push_back(strAddNode); + } + BOOST_FOREACH(string& strAddNode, lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(addr, &grant, strAddNode.c_str()); - Sleep(500); + MilliSleep(500); } - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; - Sleep(120000); // Retry every 2 minutes - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; + MilliSleep(120000); // Retry every 2 minutes } - return; } - vector > vservAddressesToAdd(0); - BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) + for (unsigned int i = 0; true; i++) { - vector vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) + list lAddresses(0); { - vservAddressesToAdd.push_back(vservNode); + LOCK(cs_vAddedNodes); + BOOST_FOREACH(string& strAddNode, vAddedNodes) + lAddresses.push_back(strAddNode); + } + + list > lservAddressesToAdd(0); + BOOST_FOREACH(string& strAddNode, lAddresses) + { + vector vservNode(0); + if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) { - LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH(CService& serv, vservNode) - setservAddNodeAddresses.insert(serv); + lservAddressesToAdd.push_back(vservNode); + { + LOCK(cs_setservAddNodeAddresses); + BOOST_FOREACH(CService& serv, vservNode) + setservAddNodeAddresses.insert(serv); + } } } - } - loop - { - vector > vservConnectAddresses = vservAddressesToAdd; // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry // (keeping in mind that addnode entries can have many IPs if fNameLookup) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) - for (vector >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++) + for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) BOOST_FOREACH(CService& addrNode, *(it)) if (pnode->addr == addrNode) { - it = vservConnectAddresses.erase(it); + it = lservAddressesToAdd.erase(it); it--; break; } } - BOOST_FOREACH(vector& vserv, vservConnectAddresses) + BOOST_FOREACH(vector& vserv, lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(*(vserv.begin())), &grant); - Sleep(500); - if (fShutdown) - return; + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); + MilliSleep(500); } - if (fShutdown) - return; - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; - Sleep(120000); // Retry every 2 minutes - vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; - if (fShutdown) - return; + MilliSleep(120000); // Retry every 2 minutes } } -// if succesful, this moves the passed grant to the constructed node +// if successful, this moves the passed grant to the constructed node bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot) { // // Initiate outbound network connection // - if (fShutdown) - return false; + boost::this_thread::interruption_point(); if (!strDest) if (IsLocal(addrConnect) || FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || @@ -1593,11 +1477,9 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu if (strDest && FindNode(strDest)) return false; - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; CNode* pnode = ConnectNode(addrConnect, strDest); - vnThreadsRunning[THREAD_OPENCONNECTIONS]++; - if (fShutdown) - return false; + boost::this_thread::interruption_point(); + if (!pnode) return false; if (grantOutbound) @@ -1610,63 +1492,94 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu } - - - - - - -void ThreadMessageHandler(void* parg) -{ - IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg)); - - // Make this thread recognisable as the message handling thread - RenameThread("bitcoin-msghand"); - - try - { - vnThreadsRunning[THREAD_MESSAGEHANDLER]++; - ThreadMessageHandler2(parg); - vnThreadsRunning[THREAD_MESSAGEHANDLER]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_MESSAGEHANDLER]--; - PrintException(&e, "ThreadMessageHandler()"); - } catch (...) { - vnThreadsRunning[THREAD_MESSAGEHANDLER]--; - PrintException(NULL, "ThreadMessageHandler()"); - } - printf("ThreadMessageHandler exited\n"); +// for now, use a very simple selection metric: the node from which we received +// most recently +double static NodeSyncScore(const CNode *pnode) { + return -pnode->nLastRecv; } -void ThreadMessageHandler2(void* parg) +void static StartSync(const vector &vNodes) { + CNode *pnodeNewSync = NULL; + double dBestScore = 0; + + // fImporting and fReindex are accessed out of cs_main here, but only + // as an optimization - they are checked again in SendMessages. + if (fImporting || fReindex) + return; + + // Iterate over all nodes + BOOST_FOREACH(CNode* pnode, vNodes) { + // check preconditions for allowing a sync + if (!pnode->fClient && !pnode->fOneShot && + !pnode->fDisconnect && pnode->fSuccessfullyConnected && + (pnode->nStartingHeight > (nBestHeight - 144)) && + (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) { + // if ok, compare node's score with the best so far + double dScore = NodeSyncScore(pnode); + if (pnodeNewSync == NULL || dScore > dBestScore) { + pnodeNewSync = pnode; + dBestScore = dScore; + } + } + } + // if a new sync candidate was found, start sync! + if (pnodeNewSync) { + pnodeNewSync->fStartSync = true; + pnodeSync = pnodeNewSync; + } +} + +void ThreadMessageHandler() { - printf("ThreadMessageHandler started\n"); SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); - while (!fShutdown) + while (true) { + bool fHaveSyncNode = false; + vector vNodesCopy; { LOCK(cs_vNodes); vNodesCopy = vNodes; - BOOST_FOREACH(CNode* pnode, vNodesCopy) + BOOST_FOREACH(CNode* pnode, vNodesCopy) { pnode->AddRef(); + if (pnode == pnodeSync) + fHaveSyncNode = true; + } } + if (!fHaveSyncNode) + StartSync(vNodesCopy); + // Poll the connected nodes for messages CNode* pnodeTrickle = NULL; if (!vNodesCopy.empty()) pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; + + bool fSleep = true; + BOOST_FOREACH(CNode* pnode, vNodesCopy) { + if (pnode->fDisconnect) + continue; + // Receive messages { - TRY_LOCK(pnode->cs_vRecv, lockRecv); + TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) - ProcessMessages(pnode); + { + if (!ProcessMessages(pnode)) + pnode->CloseSocketDisconnect(); + + if (pnode->nSendSize < SendBufferSize()) + { + if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete())) + { + fSleep = false; + } + } + } } - if (fShutdown) - return; + boost::this_thread::interruption_point(); // Send messages { @@ -1674,8 +1587,7 @@ void ThreadMessageHandler2(void* parg) if (lockSend) SendMessages(pnode, pnode == pnodeTrickle); } - if (fShutdown) - return; + boost::this_thread::interruption_point(); } { @@ -1684,16 +1596,8 @@ void ThreadMessageHandler2(void* parg) pnode->Release(); } - // Wait and allow messages to bunch up. - // Reduce vnThreadsRunning so StopNode has permission to exit while - // we're sleeping, but we must always check fShutdown after doing this. - vnThreadsRunning[THREAD_MESSAGEHANDLER]--; - Sleep(100); - if (fRequestShutdown) - StartShutdown(); - vnThreadsRunning[THREAD_MESSAGEHANDLER]++; - if (fShutdown) - return; + if (fSleep) + MilliSleep(100); } } @@ -1707,18 +1611,6 @@ bool BindListenPort(const CService &addrBind, string& strError) strError = ""; int nOne = 1; -#ifdef WIN32 - // Initialize Windows Sockets - WSADATA wsadata; - int ret = WSAStartup(MAKEWORD(2,2), &wsadata); - if (ret != NO_ERROR) - { - strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret); - printf("%s\n", strError.c_str()); - return false; - } -#endif - // Create socket for listening for incoming connections #ifdef USE_IPV6 struct sockaddr_storage sockaddr; @@ -1754,7 +1646,7 @@ bool BindListenPort(const CService &addrBind, string& strError) #ifdef WIN32 - // Set to nonblocking, incoming connections will also inherit this + // Set to non-blocking, incoming connections will also inherit this if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) #else if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) @@ -1770,8 +1662,12 @@ bool BindListenPort(const CService &addrBind, string& strError) // and enable it by default or not. Try to enable it, if possible. if (addrBind.IsIPv6()) { #ifdef IPV6_V6ONLY +#ifdef WIN32 + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)); +#else setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)); #endif +#endif #ifdef WIN32 int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */; int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */; @@ -1815,7 +1711,7 @@ void static Discover() return; #ifdef WIN32 - // Get local host ip + // Get local host IP char pszHostName[1000] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { @@ -1860,17 +1756,16 @@ void static Discover() } #endif - CreateThread(ThreadGetMyExternalIP, NULL); + // Don't use external IPv4 discovery, when -onlynet="IPv6" + if (!IsLimited(NET_IPV4)) + NewThread(ThreadGetMyExternalIP, NULL); } -void StartNode(void* parg) +void StartNode(boost::thread_group& threadGroup) { - // Make this thread recognisable as the startup thread - RenameThread("bitcoin-start"); - if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); + int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } @@ -1886,74 +1781,41 @@ void StartNode(void* parg) if (!GetBoolArg("-dnsseed", true)) printf("DNS seeding disabled\n"); else - if (!CreateThread(ThreadDNSAddressSeed, NULL)) - printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n"); + threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", &ThreadDNSAddressSeed)); +#ifdef USE_UPNP // Map ports with UPnP - if (fUseUPnP) - MapPort(); - - // Get addresses from IRC and advertise ours - if (!CreateThread(ThreadIRCSeed, NULL)) - printf("Error: CreateThread(ThreadIRCSeed) failed\n"); + MapPort(GetBoolArg("-upnp", USE_UPNP)); +#endif // Send and receive from sockets, accept connections - if (!CreateThread(ThreadSocketHandler, NULL)) - printf("Error: CreateThread(ThreadSocketHandler) failed\n"); + threadGroup.create_thread(boost::bind(&TraceThread, "net", &ThreadSocketHandler)); // Initiate outbound connections from -addnode - if (!CreateThread(ThreadOpenAddedConnections, NULL)) - printf("Error: CreateThread(ThreadOpenAddedConnections) failed\n"); + threadGroup.create_thread(boost::bind(&TraceThread, "addcon", &ThreadOpenAddedConnections)); // Initiate outbound connections - if (!CreateThread(ThreadOpenConnections, NULL)) - printf("Error: CreateThread(ThreadOpenConnections) failed\n"); + threadGroup.create_thread(boost::bind(&TraceThread, "opencon", &ThreadOpenConnections)); // Process messages - if (!CreateThread(ThreadMessageHandler, NULL)) - printf("Error: CreateThread(ThreadMessageHandler) failed\n"); + threadGroup.create_thread(boost::bind(&TraceThread, "msghand", &ThreadMessageHandler)); // Dump network addresses - if (!CreateThread(ThreadDumpAddress, NULL)) - printf("Error; CreateThread(ThreadDumpAddress) failed\n"); + threadGroup.create_thread(boost::bind(&LoopForever, "dumpaddr", &DumpAddresses, DUMP_ADDRESSES_INTERVAL * 1000)); } bool StopNode() { printf("StopNode()\n"); - fShutdown = true; + GenerateBitcoins(false, NULL); + MapPort(false); nTransactionsUpdated++; - int64 nStart = GetTime(); if (semOutbound) for (int i=0; ipost(); - do - { - int nThreadsRunning = 0; - for (int n = 0; n < THREAD_MAX; n++) - nThreadsRunning += vnThreadsRunning[n]; - if (nThreadsRunning == 0) - break; - if (GetTime() - nStart > 20) - break; - Sleep(20); - } while(true); - if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n"); - if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n"); - if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n"); - if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); - if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); - if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); -#ifdef USE_UPNP - if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n"); -#endif - if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n"); - if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n"); - if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n"); - while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0) - Sleep(20); - Sleep(50); + MilliSleep(50); DumpAddresses(); + return true; } @@ -1974,6 +1836,18 @@ public: if (closesocket(hListenSocket) == SOCKET_ERROR) printf("closesocket(hListenSocket) failed with error %d\n", 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(); + delete semOutbound; + semOutbound = NULL; + delete pnodeLocalHost; + pnodeLocalHost = NULL; + #ifdef WIN32 // Shutdown Windows Sockets WSACleanup(); @@ -1981,3 +1855,48 @@ public: } } instance_of_cnetcleanup; + + + + + + + +void RelayTransaction(const CTransaction& tx, const uint256& hash) +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(10000); + ss << tx; + RelayTransaction(tx, hash, ss); +} + +void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss) +{ + CInv inv(MSG_TX, hash); + { + LOCK(cs_mapRelay); + // Expire old relay messages + while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) + { + mapRelay.erase(vRelayExpiration.front().second); + vRelayExpiration.pop_front(); + } + + // Save original serialized message so newer versions are preserved + mapRelay.insert(std::make_pair(inv, ss)); + vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); + } + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + if(!pnode->fRelayTxes) + continue; + LOCK(pnode->cs_filter); + if (pnode->pfilter) + { + if (pnode->pfilter->IsRelevantAndUpdate(tx, hash)) + pnode->PushInventory(inv); + } else + pnode->PushInventory(inv); + } +} diff --git a/src/net.h b/src/net.h index 7feab74..0f4ba4f 100644 --- a/src/net.h +++ b/src/net.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_NET_H @@ -17,18 +15,20 @@ #endif #include "mruset.h" +#include "limitedmap.h" #include "netbase.h" #include "protocol.h" #include "addrman.h" +#include "hash.h" +#include "bloom.h" -class CRequestTracker; class CNode; class CBlockIndex; extern int nBestHeight; -inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } +inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } void AddOneShot(std::string strDest); @@ -37,12 +37,13 @@ bool GetMyExternalIP(CNetAddr& ipRet); void AddressCurrentlyConnected(const CService& addr); CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CService& ip); -CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0); -void MapPort(); +CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL); +void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string())); -void StartNode(void* parg); +void StartNode(boost::thread_group& threadGroup); bool StopNode(); +void SocketSendData(CNode *pnode); enum { @@ -50,8 +51,7 @@ enum LOCAL_IF, // address a local interface listens on LOCAL_BIND, // address explicit bound to LOCAL_UPNP, // address reported by UPnP - LOCAL_IRC, // address reported by IRC (deprecated) - LOCAL_HTTP, // address reported by whatismyip.com and similars + LOCAL_HTTP, // address reported by whatismyip.com and similar LOCAL_MANUAL, // address explicitly specified (-externalip=) LOCAL_MAX @@ -70,62 +70,21 @@ void SetReachable(enum Network net, bool fFlag = true); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); -enum -{ - MSG_TX = 1, - MSG_BLOCK, -}; - -class CRequestTracker -{ -public: - void (*fn)(void*, CDataStream&); - void* param1; - - explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL) - { - fn = fnIn; - param1 = param1In; - } - - bool IsNull() - { - return fn == NULL; - } -}; - - -/** Thread types */ -enum threadId -{ - THREAD_SOCKETHANDLER, - THREAD_OPENCONNECTIONS, - THREAD_MESSAGEHANDLER, - THREAD_MINER, - THREAD_RPCLISTENER, - THREAD_UPNP, - THREAD_DNSSEED, - THREAD_ADDEDCONNECTIONS, - THREAD_DUMPADDRESS, - THREAD_RPCHANDLER, - - THREAD_MAX -}; - -extern bool fClient; extern bool fDiscover; -extern bool fUseUPnP; extern uint64 nLocalServices; extern uint64 nLocalHostNonce; -extern boost::array vnThreadsRunning; extern CAddrMan addrman; +extern int nMaxConnections; extern std::vector vNodes; extern CCriticalSection cs_vNodes; extern std::map mapRelay; extern std::deque > vRelayExpiration; extern CCriticalSection cs_mapRelay; -extern std::map mapAlreadyAskedFor; +extern limitedmap mapAlreadyAskedFor; + +extern std::vector vAddedNodes; +extern CCriticalSection cs_vAddedNodes; @@ -139,11 +98,52 @@ public: int64 nTimeConnected; std::string addrName; int nVersion; - std::string strSubVer; + std::string cleanSubVer; bool fInbound; - int64 nReleaseTime; int nStartingHeight; int nMisbehavior; + uint64 nSendBytes; + uint64 nRecvBytes; + uint64 nBlocksRequested; + bool fSyncNode; +}; + + + + +class CNetMessage { +public: + bool in_data; // parsing header (false) or data (true) + + CDataStream hdrbuf; // partially received header + CMessageHeader hdr; // complete header + unsigned int nHdrPos; + + CDataStream vRecv; // received message data + unsigned int nDataPos; + + CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) { + hdrbuf.resize(24); + in_data = false; + nHdrPos = 0; + nDataPos = 0; + } + + bool complete() const + { + if (!in_data) + return false; + return (hdr.nMessageSize == nDataPos); + } + + void SetVersion(int nVersionIn) + { + hdrbuf.SetVersion(nVersionIn); + vRecv.SetVersion(nVersionIn); + } + + int readHeader(const char *pch, unsigned int nBytes); + int readData(const char *pch, unsigned int nBytes); }; @@ -157,45 +157,62 @@ public: // socket uint64 nServices; SOCKET hSocket; - CDataStream vSend; - CDataStream vRecv; + CDataStream ssSend; + size_t nSendSize; // total size of all vSendMsg entries + size_t nSendOffset; // offset inside the first vSendMsg already sent + uint64 nSendBytes; + std::deque vSendMsg; CCriticalSection cs_vSend; - CCriticalSection cs_vRecv; + + std::deque vRecvGetData; + std::deque vRecvMsg; + CCriticalSection cs_vRecvMsg; + uint64 nRecvBytes; + int nRecvVersion; + int64 nLastSend; int64 nLastRecv; int64 nLastSendEmpty; int64 nTimeConnected; - int nHeaderStart; - unsigned int nMessageStart; + uint64 nBlocksRequested; CAddress addr; std::string addrName; CService addrLocal; int nVersion; - std::string strSubVer; + // 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; bool fOneShot; bool fClient; bool fInbound; bool fNetworkNode; bool fSuccessfullyConnected; 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 their version message that we should not relay tx invs + // until they have initialized their bloom filter. + bool fRelayTxes; CSemaphoreGrant grantOutbound; -protected: + CCriticalSection cs_filter; + CBloomFilter* pfilter; int nRefCount; +protected: // Denial-of-service detection/prevention - // Key is ip address, value is banned-until-time + // Key is IP address, value is banned-until-time static std::map setBanned; static CCriticalSection cs_setBanned; int nMisbehavior; public: - int64 nReleaseTime; - std::map mapRequests; - CCriticalSection cs_mapRequests; uint256 hashContinue; CBlockIndex* pindexLastGetBlocksBegin; uint256 hashLastGetBlocksEnd; int nStartingHeight; + bool fStartSync; // flood relay std::vector vAddrToSend; @@ -209,16 +226,18 @@ public: CCriticalSection cs_inventory; std::multimap mapAskFor; - CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION) + CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION) { nServices = 0; hSocket = hSocketIn; + nRecvVersion = INIT_PROTO_VERSION; nLastSend = 0; nLastRecv = 0; + nSendBytes = 0; + nRecvBytes = 0; nLastSendEmpty = GetTime(); nTimeConnected = GetTime(); - nHeaderStart = -1; - nMessageStart = -1; + nBlocksRequested = 0; addr = addrIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; @@ -230,17 +249,21 @@ public: fSuccessfullyConnected = false; fDisconnect = false; nRefCount = 0; - nReleaseTime = 0; + nSendSize = 0; + nSendOffset = 0; hashContinue = 0; pindexLastGetBlocksBegin = 0; hashLastGetBlocksEnd = 0; nStartingHeight = -1; + fStartSync = false; fGetAddr = false; nMisbehavior = 0; + fRelayTxes = false; setInventoryKnown.max_size(SendBufferSize() / 1000); + pfilter = new CBloomFilter(); // Be shy and don't send version until we hear - if (!fInbound) + if (hSocket != INVALID_SOCKET && !fInbound) PushVersion(); } @@ -251,6 +274,8 @@ public: closesocket(hSocket); hSocket = INVALID_SOCKET; } + if (pfilter) + delete pfilter; } private: @@ -261,15 +286,33 @@ public: int GetRefCount() { - return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0); + assert(nRefCount >= 0); + return nRefCount; } - CNode* AddRef(int64 nTimeout=0) + // requires LOCK(cs_vRecvMsg) + unsigned int GetTotalRecvSize() { - if (nTimeout != 0) - nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout); - else - nRefCount++; + 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); + + // requires LOCK(cs_vRecvMsg) + void SetRecvVersion(int nVersionIn) + { + nRecvVersion = nVersionIn; + BOOST_FOREACH(CNetMessage &msg, vRecvMsg) + msg.SetVersion(nVersionIn); + } + + CNode* AddRef() + { + nRefCount++; return this; } @@ -316,9 +359,14 @@ public: { // We're using mapAskFor as a priority queue, // the key is the earliest time the request can be sent - int64& nRequestTime = mapAlreadyAskedFor[inv]; + int64 nRequestTime; + limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv); + if (it != mapAlreadyAskedFor.end()) + nRequestTime = it->second; + else + nRequestTime = 0; if (fDebugNet) - printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime); + printf("askfor %s %"PRI64d" (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str()); // Make sure not to reuse time indexes to keep things in the same order int64 nNow = (GetTime() - 1) * 1000000; @@ -329,37 +377,38 @@ public: // Each retry is 2 minutes after the last nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); + if (it != mapAlreadyAskedFor.end()) + mapAlreadyAskedFor.update(it, nRequestTime); + else + mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); mapAskFor.insert(std::make_pair(nRequestTime, inv)); } - void BeginMessage(const char* pszCommand) + // TODO: Document the postcondition of this function. Is cs_vSend locked? + void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) { ENTER_CRITICAL_SECTION(cs_vSend); - if (nHeaderStart != -1) - AbortMessage(); - nHeaderStart = vSend.size(); - vSend << CMessageHeader(pszCommand, 0); - nMessageStart = vSend.size(); + assert(ssSend.size() == 0); + ssSend << CMessageHeader(pszCommand, 0); if (fDebug) printf("sending: %s ", pszCommand); } - void AbortMessage() + // TODO: Document the precondition of this function. Is cs_vSend locked? + void AbortMessage() UNLOCK_FUNCTION(cs_vSend) { - if (nHeaderStart < 0) - return; - vSend.resize(nHeaderStart); - nHeaderStart = -1; - nMessageStart = -1; + ssSend.clear(); + LEAVE_CRITICAL_SECTION(cs_vSend); if (fDebug) printf("(aborted)\n"); } - void EndMessage() + // TODO: Document the precondition of this function. Is cs_vSend locked? + void EndMessage() UNLOCK_FUNCTION(cs_vSend) { if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { @@ -368,42 +417,35 @@ public: return; } - if (nHeaderStart < 0) + if (ssSend.size() == 0) return; // Set the size - unsigned int nSize = vSend.size() - nMessageStart; - memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize)); + unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; + memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); // Set the checksum - uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); + uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); - assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); - memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum)); + assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); + memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); if (fDebug) { printf("(%d bytes)\n", nSize); } - nHeaderStart = -1; - nMessageStart = -1; + std::deque::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); + LEAVE_CRITICAL_SECTION(cs_vSend); } - void EndMessageAbortIfEmpty() - { - if (nHeaderStart < 0) - return; - int nSize = vSend.size() - nMessageStart; - if (nSize > 0) - EndMessage(); - else - AbortMessage(); - } - - - void PushVersion(); @@ -427,7 +469,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1; + ssSend << a1; EndMessage(); } catch (...) @@ -443,7 +485,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2; + ssSend << a1 << a2; EndMessage(); } catch (...) @@ -459,7 +501,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3; + ssSend << a1 << a2 << a3; EndMessage(); } catch (...) @@ -475,7 +517,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3 << a4; + ssSend << a1 << a2 << a3 << a4; EndMessage(); } catch (...) @@ -491,7 +533,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3 << a4 << a5; + ssSend << a1 << a2 << a3 << a4 << a5; EndMessage(); } catch (...) @@ -507,7 +549,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3 << a4 << a5 << a6; + ssSend << a1 << a2 << a3 << a4 << a5 << a6; EndMessage(); } catch (...) @@ -523,7 +565,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; + ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; EndMessage(); } catch (...) @@ -539,7 +581,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; + ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; EndMessage(); } catch (...) @@ -555,7 +597,7 @@ public: try { BeginMessage(pszCommand); - vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; + ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; EndMessage(); } catch (...) @@ -565,53 +607,6 @@ public: } } - - void PushRequest(const char* pszCommand, - void (*fn)(void*, CDataStream&), void* param1) - { - uint256 hashReply; - RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - - { - LOCK(cs_mapRequests); - mapRequests[hashReply] = CRequestTracker(fn, param1); - } - - PushMessage(pszCommand, hashReply); - } - - template - void PushRequest(const char* pszCommand, const T1& a1, - void (*fn)(void*, CDataStream&), void* param1) - { - uint256 hashReply; - RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - - { - LOCK(cs_mapRequests); - mapRequests[hashReply] = CRequestTracker(fn, param1); - } - - PushMessage(pszCommand, hashReply, a1); - } - - template - void PushRequest(const char* pszCommand, const T1& a1, const T2& a2, - void (*fn)(void*, CDataStream&), void* param1) - { - uint256 hashReply; - RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - - { - LOCK(cs_mapRequests); - mapRequests[hashReply] = CRequestTracker(fn, param1); - } - - PushMessage(pszCommand, hashReply, a1, a2); - } - - - void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd); bool IsSubscribed(unsigned int nChannel); void Subscribe(unsigned int nChannel, unsigned int nHops=0); @@ -642,51 +637,8 @@ public: - - - - - - - -inline void RelayInventory(const CInv& inv) -{ - // Put on lists to offer to the other nodes - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - pnode->PushInventory(inv); - } -} - -template -void RelayMessage(const CInv& inv, const T& a) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(10000); - ss << a; - RelayMessage(inv, ss); -} - -template<> -inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) -{ - { - LOCK(cs_mapRelay); - // Expire old relay messages - while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) - { - mapRelay.erase(vRelayExpiration.front().second); - vRelayExpiration.pop_front(); - } - - // Save original serialized message so newer versions are preserved - mapRelay.insert(std::make_pair(inv, ss)); - vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); - } - - RelayInventory(inv); -} - +class CTransaction; +void RelayTransaction(const CTransaction& tx, const uint256& hash); +void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss); #endif diff --git a/src/netbase.cpp b/src/netbase.cpp index ca39fa5..d969516 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1,26 +1,26 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "netbase.h" #include "util.h" +#include "sync.h" +#include "hash.h" #ifndef WIN32 #include #endif -#include "strlcpy.h" #include // for to_lower() +#include // for startswith() and endswith() using namespace std; // Settings -typedef std::pair proxyType; static proxyType proxyInfo[NET_MAX]; static proxyType nameproxyInfo; +static CCriticalSection cs_proxyInfos; int nConnectTimeout = 5000; bool fNameLookup = false; @@ -31,7 +31,6 @@ enum Network ParseNetwork(std::string net) { if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; if (net == "tor") return NET_TOR; - if (net == "i2p") return NET_I2P; return NET_UNROUTABLE; } @@ -73,19 +72,14 @@ bool static LookupIntern(const char *pszName, std::vector& vIP, unsign aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_protocol = IPPROTO_TCP; -#ifdef WIN32 -# ifdef USE_IPV6 +#ifdef USE_IPV6 aiHint.ai_family = AF_UNSPEC; -# else +#else aiHint.ai_family = AF_INET; -# endif +#endif +#ifdef WIN32 aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; #else -# ifdef USE_IPV6 - aiHint.ai_family = AF_UNSPEC; -# else - aiHint.ai_family = AF_INET; -# endif aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; #endif struct addrinfo *aiRes = NULL; @@ -120,18 +114,15 @@ bool static LookupIntern(const char *pszName, std::vector& vIP, unsign bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { - if (pszName[0] == 0) + std::string strHost(pszName); + if (strHost.empty()) return false; - char psz[256]; - char *pszHost = psz; - strlcpy(psz, pszName, sizeof(psz)); - if (psz[0] == '[' && psz[strlen(psz)-1] == ']') + if (boost::algorithm::starts_with(strHost, "[") && boost::algorithm::ends_with(strHost, "]")) { - pszHost = psz+1; - psz[strlen(psz)-1] = 0; + strHost = strHost.substr(1, strHost.size() - 2); } - return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); + return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup); } bool LookupHostNumeric(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions) @@ -225,10 +216,9 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket) return error("Hostname too long"); } char pszSocks5Init[] = "\5\1\0"; - char *pszSocks5 = pszSocks5Init; ssize_t nSize = sizeof(pszSocks5Init) - 1; - ssize_t ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); + ssize_t ret = send(hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL); if (ret != nSize) { closesocket(hSocket); @@ -248,7 +238,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket) string strSocks5("\5\1"); strSocks5 += '\000'; strSocks5 += '\003'; strSocks5 += static_cast(std::min((int)strDest.size(), 255)); - strSocks5 += strDest; + strSocks5 += strDest; strSocks5 += static_cast((port >> 8) & 0xFF); strSocks5 += static_cast((port >> 0) & 0xFF); ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); @@ -417,7 +407,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else fFlags = fcntl(hSocket, F_GETFL, 0); - if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR) + if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) #endif { closesocket(hSocket); @@ -434,15 +424,17 @@ bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) { return false; if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; + LOCK(cs_proxyInfos); proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); return true; } -bool GetProxy(enum Network net, CService &addrProxy) { +bool GetProxy(enum Network net, proxyType &proxyInfoOut) { assert(net >= 0 && net < NET_MAX); + LOCK(cs_proxyInfos); if (!proxyInfo[net].second) return false; - addrProxy = proxyInfo[net].first; + proxyInfoOut = proxyInfo[net]; return true; } @@ -451,16 +443,27 @@ bool SetNameProxy(CService addrProxy, int nSocksVersion) { return false; if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; + LOCK(cs_proxyInfos); nameproxyInfo = std::make_pair(addrProxy, nSocksVersion); return true; } -bool GetNameProxy() { +bool GetNameProxy(proxyType &nameproxyInfoOut) { + LOCK(cs_proxyInfos); + if (!nameproxyInfo.second) + return false; + nameproxyInfoOut = nameproxyInfo; + return true; +} + +bool HaveNameProxy() { + LOCK(cs_proxyInfos); return nameproxyInfo.second != 0; } bool IsProxy(const CNetAddr &addr) { - for (int i=0; i11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") { - std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str()); - if (vchAddr.size() != 16-sizeof(pchGarliCat)) - return false; - memcpy(ip, pchOnionCat, sizeof(pchGarliCat)); - for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++) - ip[i + sizeof(pchGarliCat)] = vchAddr[i]; - return true; - } return false; } @@ -601,7 +597,7 @@ CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) *this = vIP[0]; } -int CNetAddr::GetByte(int n) const +unsigned int CNetAddr::GetByte(int n) const { return ip[15-n]; } @@ -613,14 +609,14 @@ bool CNetAddr::IsIPv4() const bool CNetAddr::IsIPv6() const { - return (!IsIPv4() && !IsTor() && !IsI2P()); + return (!IsIPv4() && !IsTor()); } bool CNetAddr::IsRFC1918() const { return IsIPv4() && ( - GetByte(3) == 10 || - (GetByte(3) == 192 && GetByte(2) == 168) || + GetByte(3) == 10 || + (GetByte(3) == 192 && GetByte(2) == 168) || (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); } @@ -677,11 +673,6 @@ bool CNetAddr::IsTor() const return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); } -bool CNetAddr::IsI2P() const -{ - return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0); -} - bool CNetAddr::IsLocal() const { // IPv4 loopback @@ -704,7 +695,7 @@ bool CNetAddr::IsMulticast() const bool CNetAddr::IsValid() const { - // Clean up 3-byte shifted addresses caused by garbage in size field + // 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... @@ -740,7 +731,7 @@ bool CNetAddr::IsValid() const bool CNetAddr::IsRoutable() const { - return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal()); + return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal()); } enum Network CNetAddr::GetNetwork() const @@ -754,9 +745,6 @@ enum Network CNetAddr::GetNetwork() const if (IsTor()) return NET_TOR; - if (IsI2P()) - return NET_I2P; - return NET_IPV6; } @@ -764,8 +752,6 @@ std::string CNetAddr::ToStringIP() const { if (IsTor()) return EncodeBase32(&ip[6], 10) + ".onion"; - if (IsI2P()) - return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p"; CService serv(*this, 0); #ifdef USE_IPV6 struct sockaddr_storage sockaddr; @@ -853,13 +839,13 @@ std::vector CNetAddr::GetGroup() const nClass = NET_IPV4; nStartByte = 12; } - // for 6to4 tunneled addresses, use the encapsulated IPv4 address + // for 6to4 tunnelled addresses, use the encapsulated IPv4 address else if (IsRFC3964()) { nClass = NET_IPV4; nStartByte = 2; } - // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address + // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address else if (IsRFC4380()) { vchRet.push_back(NET_IPV4); @@ -873,14 +859,8 @@ std::vector CNetAddr::GetGroup() const nStartByte = 6; nBits = 4; } - else if (IsI2P()) - { - nClass = NET_I2P; - nStartByte = 6; - nBits = 4; - } // for he.net, use /36 groups - else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) + 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 @@ -956,7 +936,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const 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 tunneled + 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) { @@ -964,11 +944,6 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well case NET_TOR: return REACH_PRIVATE; } - case NET_I2P: - switch(ourNet) { - default: return REACH_DEFAULT; - case NET_I2P: return REACH_PRIVATE; - } case NET_TEREDO: switch(ourNet) { default: return REACH_DEFAULT; @@ -984,8 +959,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const case NET_TEREDO: return REACH_TEREDO; case NET_IPV6: return REACH_IPV6_WEAK; case NET_IPV4: return REACH_IPV4; - case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are - case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address + case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address } } } @@ -1137,12 +1111,12 @@ std::vector CService::GetKey() const std::string CService::ToStringPort() const { - return strprintf("%i", port); + return strprintf("%u", port); } std::string CService::ToStringIPPort() const { - if (IsIPv4() || IsTor() || IsI2P()) { + if (IsIPv4() || IsTor()) { return ToStringIP() + ":" + ToStringPort(); } else { return "[" + ToStringIP() + "]:" + ToStringPort(); diff --git a/src/netbase.h b/src/netbase.h index f23e433..e4ec4ef 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -1,6 +1,4 @@ // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_NETBASE_H @@ -25,7 +23,6 @@ enum Network NET_IPV4, NET_IPV6, NET_TOR, - NET_I2P, NET_MAX, }; @@ -46,21 +43,20 @@ class CNetAddr explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); void Init(); void SetIP(const CNetAddr& ip); - bool SetSpecial(const std::string &strName); // for Tor and I2P addresses + 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/I2P) + 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 IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) - bool IsRFC3964() const; // IPv6 6to4 tunneling (2002::/16) + bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) bool IsRFC4193() const; // IPv6 unique local (FC00::/15) - bool IsRFC4380() const; // IPv6 Teredo tunneling (2001::/32) + 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 IsI2P() const; bool IsLocal() const; bool IsRoutable() const; bool IsValid() const; @@ -68,7 +64,7 @@ class CNetAddr enum Network GetNetwork() const; std::string ToString() const; std::string ToStringIP() const; - int GetByte(int n) const; + unsigned int GetByte(int n) const; uint64 GetHash() const; bool GetInAddr(struct in_addr* pipv4Addr) const; std::vector GetGroup() const; @@ -135,13 +131,15 @@ class CService : public CNetAddr ) }; +typedef std::pair proxyType; + enum Network ParseNetwork(std::string net); void SplitHostPort(std::string in, int &portOut, std::string &hostOut); bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); -bool GetProxy(enum Network net, CService &addrProxy); +bool GetProxy(enum Network net, proxyType &proxyInfoOut); bool IsProxy(const CNetAddr &addr); bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); -bool GetNameProxy(); +bool HaveNameProxy(); bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool LookupHostNumeric(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0); bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); diff --git a/src/noui.cpp b/src/noui.cpp index 81183cc..c0e00c4 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -1,30 +1,51 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "ui_interface.h" #include "init.h" #include "bitcoinrpc.h" #include -static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { - printf("%s: %s\n", caption.c_str(), message.c_str()); - fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); - return 4; + std::string strCaption; + // Check for usage of predefined caption + switch (style) { + case CClientUIInterface::MSG_ERROR: + strCaption += _("Error"); + break; + case CClientUIInterface::MSG_WARNING: + strCaption += _("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + strCaption += _("Information"); + break; + default: + strCaption += caption; // Use supplied caption (can be empty) + } + + printf("%s: %s\n", strCaption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str()); + return false; } -static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/) { return true; } +static void noui_InitMessage(const std::string &message) +{ + printf("init message: %s\n", message.c_str()); +} + void noui_connect() { // Connect bitcoind signal handlers uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox); uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee); + uiInterface.InitMessage.connect(noui_InitMessage); } diff --git a/src/obj-test/.gitignore b/src/obj-test/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/src/obj-test/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/protocol.cpp b/src/protocol.cpp index 9c0c1b9..88bbe49 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,13 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "protocol.h" #include "util.h" #include "netbase.h" +#include "main.h" #ifndef WIN32 # include @@ -18,6 +17,7 @@ static const char* ppszTypeName[] = "ERROR", "tx", "block", + "filtered block" }; CMessageHeader::CMessageHeader() @@ -142,7 +142,7 @@ const char* CInv::GetCommand() const std::string CInv::ToString() const { - return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str()); + return strprintf("%s %s", GetCommand(), hash.ToString().c_str()); } void CInv::print() const diff --git a/src/protocol.h b/src/protocol.h index 39b682f..5e0f8c4 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -58,7 +56,8 @@ class CMessageHeader CHECKSUM_SIZE=sizeof(int), MESSAGE_SIZE_OFFSET=MESSAGE_START_SIZE+COMMAND_SIZE, - CHECKSUM_OFFSET=MESSAGE_SIZE_OFFSET+MESSAGE_SIZE_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]; @@ -70,6 +69,7 @@ class CMessageHeader enum { NODE_NETWORK = (1 << 0), + NODE_BLOOM = (1 << 1), }; /** A CService with information about it as peer */ @@ -136,4 +136,13 @@ class CInv uint256 hash; }; +enum +{ + MSG_TX = 1, + MSG_BLOCK, + // Nodes may always request a MSG_FILTERED_BLOCK in a getdata, however, + // MSG_FILTERED_BLOCK should not appear in any invs except as a part of getdata. + MSG_FILTERED_BLOCK, +}; + #endif // __INCLUDED_PROTOCOL_H__ diff --git a/src/qt/aboutdialog.cpp b/src/qt/aboutdialog.cpp index 0b98bef..4b6b5e7 100644 --- a/src/qt/aboutdialog.cpp +++ b/src/qt/aboutdialog.cpp @@ -1,14 +1,21 @@ #include "aboutdialog.h" #include "ui_aboutdialog.h" -#include "clientmodel.h" -#include "version.h" +#include "clientmodel.h" +#include "clientversion.h" + +// Copyright year (2009-this) +// Todo: update this when changing our copyright comments in the source +const int ABOUTDIALOG_COPYRIGHT_YEAR = 2013; AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); + + // Set current copyright year + ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString("
") + tr("Copyright") + QString(" © ") + tr("2013-%1 The CasinoCoin developers").arg(ABOUTDIALOG_COPYRIGHT_YEAR)); } void AboutDialog::setModel(ClientModel *model) diff --git a/src/qt/aboutdialog.h b/src/qt/aboutdialog.h index 2ed9e9e..33b1437 100644 --- a/src/qt/aboutdialog.h +++ b/src/qt/aboutdialog.h @@ -18,6 +18,7 @@ public: ~AboutDialog(); void setModel(ClientModel *model); + private: Ui::AboutDialog *ui; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 8a74a47..5574478 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -8,15 +8,15 @@ #include "csvmodelwriter.h" #include "guiutil.h" +#ifdef USE_QRCODE +#include "qrcodedialog.h" +#endif + #include #include #include #include -#ifdef USE_QRCODE -#include "qrcodedialog.h" -#endif - AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : QDialog(parent), ui(new Ui::AddressBookPage), @@ -27,10 +27,13 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : { ui->setupUi(this); -#ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac - ui->newAddressButton->setIcon(QIcon()); - ui->copyToClipboard->setIcon(QIcon()); - ui->deleteButton->setIcon(QIcon()); +#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac + ui->newAddress->setIcon(QIcon()); + ui->copyAddress->setIcon(QIcon()); + ui->deleteAddress->setIcon(QIcon()); + ui->verifyMessage->setIcon(QIcon()); + ui->signMessage->setIcon(QIcon()); + ui->exportButton->setIcon(QIcon()); #endif #ifndef USE_QRCODE @@ -43,6 +46,7 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept())); ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableView->setFocus(); + ui->exportButton->hide(); break; case ForEditing: ui->buttonBox->setVisible(false); @@ -51,24 +55,26 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : switch(tab) { case SendingTab: - ui->labelExplanation->setVisible(false); - ui->deleteButton->setVisible(true); + ui->labelExplanation->setText(tr("These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins.")); + ui->deleteAddress->setVisible(true); ui->signMessage->setVisible(false); break; case ReceivingTab: - ui->deleteButton->setVisible(false); + ui->labelExplanation->setText(tr("These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you.")); + ui->deleteAddress->setVisible(false); ui->signMessage->setVisible(true); break; } // Context menu actions + QAction *copyAddressAction = new QAction(ui->copyAddress->text(), this); QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); - QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this); QAction *editAction = new QAction(tr("&Edit"), this); + QAction *sendCoinsAction = new QAction(tr("Send &Coins"), this); QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this); QAction *signMessageAction = new QAction(ui->signMessage->text(), this); QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this); - deleteAction = new QAction(ui->deleteButton->text(), this); + deleteAction = new QAction(ui->deleteAddress->text(), this); // Build context menu contextMenu = new QMenu(); @@ -78,17 +84,22 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : if(tab == SendingTab) contextMenu->addAction(deleteAction); contextMenu->addSeparator(); + if(tab == SendingTab) + contextMenu->addAction(sendCoinsAction); +#ifdef USE_QRCODE contextMenu->addAction(showQRCodeAction); +#endif if(tab == ReceivingTab) contextMenu->addAction(signMessageAction); else if(tab == SendingTab) contextMenu->addAction(verifyMessageAction); // Connect signals for context menu actions - connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked())); + connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction())); connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction())); - connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked())); + connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(onSendCoinsAction())); connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked())); connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked())); connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked())); @@ -132,17 +143,19 @@ void AddressBookPage::setModel(AddressTableModel *model) ui->tableView->sortByColumn(0, Qt::AscendingOrder); // Set column widths - ui->tableView->horizontalHeader()->resizeSection( - AddressTableModel::Address, 320); - ui->tableView->horizontalHeader()->setResizeMode( - AddressTableModel::Label, QHeaderView::Stretch); +#if QT_VERSION < 0x050000 + ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch); + ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); +#else + ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch); + ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); +#endif connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), 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(); } @@ -152,7 +165,7 @@ void AddressBookPage::setOptionsModel(OptionsModel *optionsModel) this->optionsModel = optionsModel; } -void AddressBookPage::on_copyToClipboard_clicked() +void AddressBookPage::on_copyAddress_clicked() { GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address); } @@ -184,36 +197,43 @@ void AddressBookPage::on_signMessage_clicked() { QTableView *table = ui->tableView; QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - QString addr; foreach (QModelIndex index, indexes) { - QVariant address = index.data(); - addr = address.toString(); + QString address = index.data().toString(); + emit signMessage(address); } - - emit signMessage(addr); } void AddressBookPage::on_verifyMessage_clicked() { QTableView *table = ui->tableView; QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - QString addr; foreach (QModelIndex index, indexes) { - QVariant address = index.data(); - addr = address.toString(); + QString address = index.data().toString(); + emit verifyMessage(address); } - - emit verifyMessage(addr); } -void AddressBookPage::on_newAddressButton_clicked() +void AddressBookPage::onSendCoinsAction() +{ + QTableView *table = ui->tableView; + QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); + + foreach (QModelIndex index, indexes) + { + QString address = index.data().toString(); + emit sendCoins(address); + } +} + +void AddressBookPage::on_newAddress_clicked() { if(!model) return; + EditAddressDialog dlg( tab == SendingTab ? EditAddressDialog::NewSendingAddress : @@ -225,11 +245,12 @@ void AddressBookPage::on_newAddressButton_clicked() } } -void AddressBookPage::on_deleteButton_clicked() +void AddressBookPage::on_deleteAddress_clicked() { QTableView *table = ui->tableView; if(!table->selectionModel()) return; + QModelIndexList indexes = table->selectionModel()->selectedRows(); if(!indexes.isEmpty()) { @@ -250,8 +271,8 @@ void AddressBookPage::selectionChanged() { case SendingTab: // In sending tab, allow deletion of selection - ui->deleteButton->setEnabled(true); - ui->deleteButton->setVisible(true); + ui->deleteAddress->setEnabled(true); + ui->deleteAddress->setVisible(true); deleteAction->setEnabled(true); ui->signMessage->setEnabled(false); ui->signMessage->setVisible(false); @@ -260,8 +281,8 @@ void AddressBookPage::selectionChanged() break; case ReceivingTab: // Deleting receiving addresses, however, is not allowed - ui->deleteButton->setEnabled(false); - ui->deleteButton->setVisible(false); + ui->deleteAddress->setEnabled(false); + ui->deleteAddress->setVisible(false); deleteAction->setEnabled(false); ui->signMessage->setEnabled(true); ui->signMessage->setVisible(true); @@ -269,14 +290,14 @@ void AddressBookPage::selectionChanged() ui->verifyMessage->setVisible(false); break; } - ui->copyToClipboard->setEnabled(true); + ui->copyAddress->setEnabled(true); ui->showQRCode->setEnabled(true); } else { - ui->deleteButton->setEnabled(false); + ui->deleteAddress->setEnabled(false); ui->showQRCode->setEnabled(false); - ui->copyToClipboard->setEnabled(false); + ui->copyAddress->setEnabled(false); ui->signMessage->setEnabled(false); ui->verifyMessage->setEnabled(false); } @@ -309,7 +330,7 @@ void AddressBookPage::done(int retval) QDialog::done(retval); } -void AddressBookPage::exportClicked() +void AddressBookPage::on_exportButton_clicked() { // CSV is currently the only supported format QString filename = GUIUtil::getSaveFileName( @@ -341,11 +362,11 @@ void AddressBookPage::on_showQRCode_clicked() foreach (QModelIndex index, indexes) { - QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(); + QString address = index.data().toString(); + QString label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(); QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this); - if(optionsModel) - dialog->setModel(optionsModel); + dialog->setModel(optionsModel); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } @@ -361,7 +382,7 @@ void AddressBookPage::contextualMenu(const QPoint &point) } } -void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end) +void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/) { QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent)); if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect)) diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index df87486..34465aa 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -43,7 +43,6 @@ public: public slots: void done(int retval); - void exportClicked(); private: Ui::AddressBookPage *ui; @@ -54,32 +53,42 @@ private: QString returnValue; QSortFilterProxyModel *proxyModel; QMenu *contextMenu; - QAction *deleteAction; + QAction *deleteAction; // to be able to explicitly disable it QString newAddressToSelect; private slots: - void on_deleteButton_clicked(); - void on_newAddressButton_clicked(); + /** Delete currently selected address entry */ + void on_deleteAddress_clicked(); + /** Create a new address for receiving coins and / or add a new address book entry */ + void on_newAddress_clicked(); /** Copy address of currently selected address entry to clipboard */ - void on_copyToClipboard_clicked(); + void on_copyAddress_clicked(); + /** Open the sign message tab in the Sign/Verify Message dialog with currently selected address */ void on_signMessage_clicked(); + /** Open the verify message tab in the Sign/Verify Message dialog with currently selected address */ void on_verifyMessage_clicked(); - void selectionChanged(); + /** Open send coins dialog for currently selected address (no button) */ + void onSendCoinsAction(); + /** Generate a QR Code from the currently selected address */ void on_showQRCode_clicked(); + /** Copy label of currently selected address entry to clipboard (no button) */ + void onCopyLabelAction(); + /** Edit currently selected address entry (no button) */ + void onEditAction(); + /** Export button clicked */ + void on_exportButton_clicked(); + + /** Set button states based on selected tab and selection */ + void selectionChanged(); /** Spawn contextual menu (right mouse menu) for address book entry */ void contextualMenu(const QPoint &point); - - /** Copy label of currently selected address entry to clipboard */ - void onCopyLabelAction(); - /** Edit currently selected address entry */ - void onEditAction(); - /** New entry/entries were added to address table */ - void selectNewAddress(const QModelIndex &parent, int begin, int end); + void selectNewAddress(const QModelIndex &parent, int begin, int /*end*/); signals: void signMessage(QString addr); void verifyMessage(QString addr); + void sendCoins(QString addr); }; -#endif // ADDRESSBOOKDIALOG_H +#endif // ADDRESSBOOKPAGE_H diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index e65d391..1801444 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -1,4 +1,5 @@ #include "addresstablemodel.h" + #include "guiutil.h" #include "walletmodel.h" @@ -6,7 +7,6 @@ #include "base58.h" #include -#include const QString AddressTableModel::Send = "S"; const QString AddressTableModel::Receive = "R"; @@ -69,6 +69,8 @@ public: QString::fromStdString(address.ToString()))); } } + // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order + qSort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); } void updateEntry(const QString &address, const QString &label, bool isMine, int status) @@ -208,7 +210,7 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const return QVariant(); } -bool AddressTableModel::setData(const QModelIndex & index, const QVariant & value, int role) +bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if(!index.isValid()) return false; @@ -221,18 +223,36 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu switch(index.column()) { case Label: + // Do nothing, if old label == new label + if(rec->label == value.toString()) + { + editStatus = NO_CHANGES; + return false; + } wallet->SetAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get(), value.toString().toStdString()); - rec->label = value.toString(); break; case Address: + // Do nothing, if old address == new address + if(CBitcoinAddress(rec->address.toStdString()) == CBitcoinAddress(value.toString().toStdString())) + { + editStatus = NO_CHANGES; + return false; + } // Refuse to set invalid address, set error status and return false - if(!walletModel->validateAddress(value.toString())) + else if(!walletModel->validateAddress(value.toString())) { editStatus = INVALID_ADDRESS; return false; } + // Check for duplicate addresses to prevent accidental deletion of addresses, if you try + // to paste an existing address over another address (with a different label) + else if(wallet->mapAddressBook.count(CBitcoinAddress(value.toString().toStdString()).Get())) + { + editStatus = DUPLICATE_ADDRESS; + return false; + } // Double-check that we're not overwriting a receiving address - if(rec->type == AddressTableEntry::Sending) + else if(rec->type == AddressTableEntry::Sending) { { LOCK(wallet->cs_wallet); @@ -244,7 +264,6 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu } break; } - return true; } return false; @@ -262,7 +281,7 @@ QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, return QVariant(); } -Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const +Qt::ItemFlags AddressTableModel::flags(const QModelIndex &index) const { if(!index.isValid()) return 0; @@ -279,7 +298,7 @@ Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const return retval; } -QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & parent) const +QModelIndex AddressTableModel::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent); AddressTableEntry *data = priv->index(row); @@ -345,6 +364,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con { return QString(); } + // Add entry { LOCK(wallet->cs_wallet); @@ -353,7 +373,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString::fromStdString(strAddress); } -bool AddressTableModel::removeRows(int row, int count, const QModelIndex & parent) +bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(parent); AddressTableEntry *rec = priv->index(row); diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 42974e3..48baff5 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -14,6 +14,7 @@ class WalletModel; class AddressTableModel : public QAbstractTableModel { Q_OBJECT + public: explicit AddressTableModel(CWallet *wallet, WalletModel *parent = 0); ~AddressTableModel(); @@ -29,26 +30,27 @@ public: /** Return status of edit/insert operation */ enum EditStatus { - OK, - INVALID_ADDRESS, /**< Unparseable address */ - DUPLICATE_ADDRESS, /**< Address already in address book */ - WALLET_UNLOCK_FAILURE, /**< Wallet could not be unlocked to create new receiving address */ - KEY_GENERATION_FAILURE /**< Generating a new public key for a receiving address failed */ + OK, /**< Everything ok */ + NO_CHANGES, /**< No changes were made during edit operation */ + INVALID_ADDRESS, /**< Unparseable address */ + DUPLICATE_ADDRESS, /**< Address already in address book */ + WALLET_UNLOCK_FAILURE, /**< Wallet could not be unlocked to create new receiving address */ + KEY_GENERATION_FAILURE /**< Generating a new public key for a receiving address failed */ }; - static const QString Send; /**< Specifies send address */ - static const QString Receive; /**< Specifies receive address */ + static const QString Send; /**< Specifies send address */ + static const QString Receive; /**< Specifies receive address */ /** @name Methods overridden from QAbstractTableModel @{*/ int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; - bool setData(const QModelIndex & index, const QVariant & value, int role); + bool setData(const QModelIndex &index, const QVariant &value, int role); QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QModelIndex index(int row, int column, const QModelIndex & parent) const; - bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()); - Qt::ItemFlags flags(const QModelIndex & index) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + Qt::ItemFlags flags(const QModelIndex &index) const; /*@}*/ /* Add an address to the model. diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 7a2b64b..5362e37 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -19,7 +19,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) : ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE); ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE); ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE); - + // Setup Caps Lock detection. ui->passEdit1->installEventFilter(this); ui->passEdit2->installEventFilter(this); @@ -98,7 +98,7 @@ void AskPassphraseDialog::accept() break; } QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"), - tr("WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR CASINOCOINS!\nAre you sure you wish to encrypt your wallet?"), + tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR CASINOCOINS!") + "

" + tr("Are you sure you wish to encrypt your wallet?"), QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Cancel); if(retval == QMessageBox::Yes) @@ -108,7 +108,16 @@ void AskPassphraseDialog::accept() if(model->setWalletEncrypted(true, newpass1)) { QMessageBox::warning(this, tr("Wallet encrypted"), - tr("CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer.")); + "" + + tr("CasinoCoin will close now to finish the encryption process. " + "Remember that encrypting your wallet cannot fully protect " + "your casinocoins from being stolen by malware infecting your computer.") + + "

" + + tr("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.") + + "
"); QApplication::quit(); } else @@ -177,7 +186,7 @@ void AskPassphraseDialog::accept() void AskPassphraseDialog::textChanged() { - // Validate input, set Ok button to enabled when accepable + // Validate input, set Ok button to enabled when acceptable bool acceptable = false; switch(mode) { @@ -204,7 +213,7 @@ bool AskPassphraseDialog::event(QEvent *event) fCapsLock = !fCapsLock; } if (fCapsLock) { - ui->capsLabel->setText(tr("Warning: The Caps Lock key is on.")); + ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); } else { ui->capsLabel->clear(); } @@ -212,7 +221,7 @@ bool AskPassphraseDialog::event(QEvent *event) return QWidget::event(event); } -bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event) +bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event) { /* Detect Caps Lock. * There is no good OS-independent way to check a key state in Qt, but we @@ -226,14 +235,14 @@ bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event) if (str.length() != 0) { const QChar *psz = str.unicode(); bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0; - if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) { + if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) { fCapsLock = true; - ui->capsLabel->setText(tr("Warning: The Caps Lock key is on.")); + ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); } else if (psz->isLetter()) { fCapsLock = false; ui->capsLabel->clear(); } } } - return false; + return QDialog::eventFilter(object, event); } diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index b500ff4..9df002d 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -6,7 +6,6 @@ namespace Ui { class AskPassphraseDialog; } - class WalletModel; /** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase. @@ -39,7 +38,7 @@ private: private slots: void textChanged(); bool event(QEvent *event); - bool eventFilter(QObject *, QEvent *event); + bool eventFilter(QObject *object, QEvent *event); }; #endif // ASKPASSPHRASEDIALOG_H diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a99de62..9ed241a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -1,27 +1,33 @@ /* * W.J. van der Laan 2011-2012 */ + +#include + #include "bitcoingui.h" #include "clientmodel.h" #include "walletmodel.h" #include "optionsmodel.h" #include "guiutil.h" #include "guiconstants.h" - #include "init.h" +#include "util.h" #include "ui_interface.h" -#include "qtipcserver.h" +#include "paymentserver.h" +#include "splashscreen.h" -#include #include +#if QT_VERSION < 0x050000 #include +#endif #include +#include #include -#include #include -#include -#include +#ifdef Q_OS_MAC +#include "macdockiconhandler.h" +#endif #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) #define _BITCOIN_QT_PLUGINS_INCLUDED @@ -34,36 +40,44 @@ Q_IMPORT_PLUGIN(qkrcodecs) Q_IMPORT_PLUGIN(qtaccessiblewidgets) #endif +// Declare meta types used for QMetaObject::invokeMethod +Q_DECLARE_METATYPE(bool*) + // Need a global reference for the notifications to find the GUI static BitcoinGUI *guiref; -static QSplashScreen *splashref; +static SplashScreen *splashref; -static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { // Message from network thread if(guiref) { bool modal = (style & CClientUIInterface::MODAL); - // in case of modal message, use blocking connection to wait for user to click OK - QMetaObject::invokeMethod(guiref, "error", + bool ret = false; + // In case of modal message, use blocking connection to wait for user to click a button + QMetaObject::invokeMethod(guiref, "message", modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(caption)), Q_ARG(QString, QString::fromStdString(message)), - Q_ARG(bool, modal)); + Q_ARG(unsigned int, style), + Q_ARG(bool*, &ret)); + return ret; } else { printf("%s: %s\n", caption.c_str(), message.c_str()); fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + return false; } } -static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool ThreadSafeAskFee(int64 nFeeRequired) { if(!guiref) return false; - if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) + if(nFeeRequired < CTransaction::nMinTxFee || nFeeRequired <= nTransactionFee || fDaemon) return true; + bool payFee = false; QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), @@ -73,27 +87,14 @@ static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) return payFee; } -static void ThreadSafeHandleURI(const std::string& strURI) -{ - if(!guiref) - return; - - QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(), - Q_ARG(QString, QString::fromStdString(strURI))); -} - static void InitMessage(const std::string &message) { if(splashref) { - splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200)); - QApplication::instance()->processEvents(); + splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(55,55,55)); + qApp->processEvents(); } -} - -static void QueueShutdown() -{ - QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); + printf("init message: %s\n", message.c_str()); } /* @@ -109,72 +110,56 @@ static std::string Translate(const char* psz) static void handleRunawayException(std::exception *e) { PrintExceptionContinue(e, "Runaway exception"); - QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occured. CasinoCoin can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning)); + QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. CasinoCoin can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning)); exit(1); } #ifndef BITCOIN_QT_TEST int main(int argc, char *argv[]) { -// TODO: implement URI support on the Mac. -#if !defined(MAC_OSX) - // Do this early as we don't want to bother initializing if we are just calling IPC - for (int i = 1; i < argc; i++) - { - if (boost::algorithm::istarts_with(argv[i], "casinocoin:")) - { - const char *strURI = argv[i]; - try { - boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME); - if (mq.try_send(strURI, strlen(strURI), 0)) - // if URI could be sent to the message queue exit here - exit(0); - else - // if URI could not be sent to the message queue do a normal Bitcoin-Qt startup - break; - } - catch (boost::interprocess::interprocess_exception &ex) { - // don't log the "file not found" exception, because that's normal for - // the first start of the first instance - if (ex.get_error_code() != boost::interprocess::not_found_error) - { - printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what()); - break; - } - } - } - } -#endif + // Command-line options take precedence: + ParseParameters(argc, argv); +#if QT_VERSION < 0x050000 // Internal string conversion is all UTF-8 QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); +#endif Q_INIT_RESOURCE(bitcoin); QApplication app(argc, argv); + // Register meta types used for QMetaObject::invokeMethod + qRegisterMetaType< bool* >(); + + // Do this early as we don't want to bother initializing if we are just calling IPC + // ... but do it after creating app, so QCoreApplication::arguments is initialized: + if (PaymentServer::ipcSendCommandLine()) + exit(0); + PaymentServer* paymentServer = new PaymentServer(&app); + // Install global event filter that makes sure that long tooltips can be word-wrapped app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); - // Command-line options take precedence: - ParseParameters(argc, argv); - // ... then bitcoin.conf: if (!boost::filesystem::is_directory(GetDataDir(false))) { - fprintf(stderr, "Error: Specified directory does not exist\n"); + // This message can not be translated, as translation is not initialized yet + // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory) + QMessageBox::critical(0, "CasinoCoin", + QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); return 1; } ReadConfigFile(mapArgs, mapMultiArgs); // Application identification (must be set before OptionsModel is initialized, // as it is used to locate QSettings) - app.setOrganizationName("CasinoCoin"); - app.setOrganizationDomain("casinocoin.org"); + QApplication::setOrganizationName("CasinoCoin"); + QApplication::setOrganizationDomain("casinocoin.org"); if(GetBoolArg("-testnet")) // Separate UI settings for testnet - app.setApplicationName("CasinoCoin-Qt-testnet"); + QApplication::setApplicationName("CasinoCoin-Qt-testnet"); else - app.setApplicationName("CasinoCoin-Qt"); + QApplication::setApplicationName("CasinoCoin-Qt"); // ... then GUI settings: OptionsModel optionsModel; @@ -209,9 +194,7 @@ int main(int argc, char *argv[]) // Subscribe to global signals from core uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); - uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI); uiInterface.InitMessage.connect(InitMessage); - uiInterface.QueueShutdown.connect(QueueShutdown); uiInterface.Translate.connect(Translate); // Show help message immediately after parsing command-line options (for "-lang") and setting locale, @@ -223,7 +206,14 @@ int main(int argc, char *argv[]) return 1; } - QSplashScreen splash(QPixmap(":/images/splash"), 0); +#ifdef Q_OS_MAC + // on mac, also change the icon now because it would look strange to have a testnet splash (green) and a std app icon (orange) + if(GetBoolArg("-testnet")) { + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); + } +#endif + + SplashScreen splash(QPixmap(), 0); if (GetBoolArg("-splash", true) && !GetBoolArg("-min")) { splash.show(); @@ -232,18 +222,27 @@ int main(int argc, char *argv[]) } app.processEvents(); - app.setQuitOnLastWindowClosed(false); try { +#ifndef Q_OS_MAC // Regenerate startup link, to fix links to old versions + // OSX: makes no sense on mac and might also scan/mount external (and sleeping) volumes (can take up some secs) if (GUIUtil::GetStartOnSystemStartup()) GUIUtil::SetStartOnSystemStartup(true); +#endif + + boost::thread_group threadGroup; BitcoinGUI window; guiref = &window; - if(AppInit2()) + + QTimer* pollShutdownTimer = new QTimer(guiref); + QObject::connect(pollShutdownTimer, SIGNAL(timeout()), guiref, SLOT(detectShutdown())); + pollShutdownTimer->start(200); + + if(AppInit2(threadGroup)) { { // Put this in a block, so that the Model objects are cleaned up before @@ -255,10 +254,16 @@ int main(int argc, char *argv[]) splash.finish(&window); ClientModel clientModel(&optionsModel); - WalletModel walletModel(pwalletMain, &optionsModel); + WalletModel *walletModel = 0; + if(pwalletMain) + walletModel = new WalletModel(pwalletMain, &optionsModel); window.setClientModel(&clientModel); - window.setWalletModel(&walletModel); + if(walletModel) + { + window.addWallet("~Default", walletModel); + window.setCurrentWallet("~Default"); + } // If -min option passed, start window minimized. if(GetBoolArg("-min")) @@ -269,41 +274,30 @@ int main(int argc, char *argv[]) { window.show(); } -// TODO: implement URI support on the Mac. -#if !defined(MAC_OSX) - // Place this here as guiref has to be defined if we dont want to lose URIs - ipcInit(); + // Now that initialization/startup is done, process any command-line + // bitcoin: URIs + QObject::connect(paymentServer, SIGNAL(receivedURI(QString)), &window, SLOT(handleURI(QString))); + QTimer::singleShot(100, paymentServer, SLOT(uiReady())); - // Check for URI in argv - for (int i = 1; i < argc; i++) - { - if (boost::algorithm::istarts_with(argv[i], "casinocoin:")) - { - const char *strURI = argv[i]; - try { - boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME); - mq.try_send(strURI, strlen(strURI), 0); - } - catch (boost::interprocess::interprocess_exception &ex) { - printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what()); - break; - } - } - } -#endif app.exec(); window.hide(); window.setClientModel(0); - window.setWalletModel(0); + window.removeAllWallets(); guiref = 0; + delete walletModel; } - // Shutdown the core and it's threads, but don't exit Bitcoin-Qt here - Shutdown(NULL); + // Shutdown the core and its threads, but don't exit Bitcoin-Qt here + threadGroup.interrupt_all(); + threadGroup.join_all(); + Shutdown(); } else { + threadGroup.interrupt_all(); + threadGroup.join_all(); + Shutdown(); return 1; } } catch (std::exception& e) { diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 9733abd..57c1ace 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -1,4 +1,4 @@ - + res/icons/bitcoin.png res/icons/address-book.png @@ -30,10 +30,10 @@ res/icons/export.png res/icons/synced.png res/icons/remove.png + res/icons/tx_mined.png res/icons/tx_input.png res/icons/tx_output.png res/icons/tx_inout.png - res/icons/tx_mined.png res/icons/lock_closed.png res/icons/lock_open.png res/icons/key.png @@ -43,20 +43,27 @@ res/images/about.png - res/images/splash2.jpg + res/images/splash.png + res/images/splash_testnet.png res/images/wallet.png res/movies/update_spinner.mng + locale/bitcoin_af_ZA.qm + locale/bitcoin_ar.qm locale/bitcoin_bg.qm + locale/bitcoin_bs.ts + locale/bitcoin_ca.ts locale/bitcoin_ca_ES.qm locale/bitcoin_cs.qm + locale/bitcoin_cy.ts locale/bitcoin_da.qm locale/bitcoin_de.qm locale/bitcoin_el_GR.qm locale/bitcoin_en.qm + locale/bitcoin_eo.ts locale/bitcoin_es.qm locale/bitcoin_es_CL.qm locale/bitcoin_et.qm @@ -66,11 +73,16 @@ locale/bitcoin_fi.qm locale/bitcoin_fr.qm locale/bitcoin_fr_CA.qm + locale/bitcoin_gu_IN.ts locale/bitcoin_he.qm + locale/bitcoin_hi_IN.ts locale/bitcoin_hr.qm locale/bitcoin_hu.qm locale/bitcoin_it.qm + locale/bitcoin_ja.ts + locale/bitcoin_la.ts locale/bitcoin_lt.qm + locale/bitcoin_lv_LV.ts locale/bitcoin_nb.qm locale/bitcoin_nl.qm locale/bitcoin_pl.qm @@ -81,6 +93,7 @@ locale/bitcoin_sk.qm locale/bitcoin_sr.qm locale/bitcoin_sv.qm + locale/bitcoin_th_TH.ts locale/bitcoin_tr.qm locale/bitcoin_uk.qm locale/bitcoin_zh_CN.qm diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp index d2b93e7..5136ea0 100644 --- a/src/qt/bitcoinaddressvalidator.cpp +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -5,8 +5,8 @@ This is: - All numbers except for '0' - - All uppercase letters except for 'I' and 'O' - - All lowercase letters except for 'l' + - All upper-case letters except for 'I' and 'O' + - All lower-case letters except for 'l' User friendly Base58 input can map - 'l' and 'I' to '1' diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h index 9710d12..b7f4dfe 100644 --- a/src/qt/bitcoinaddressvalidator.h +++ b/src/qt/bitcoinaddressvalidator.h @@ -1,24 +1,21 @@ #ifndef BITCOINADDRESSVALIDATOR_H #define BITCOINADDRESSVALIDATOR_H -#include +#include -/** Base48 entry widget validator. - Corrects near-miss characters and refuses characters that are no part of base48. +/** Base58 entry widget validator. + Corrects near-miss characters and refuses characters that are not part of base58. */ class BitcoinAddressValidator : public QValidator { Q_OBJECT + public: explicit BitcoinAddressValidator(QObject *parent = 0); State validate(QString &input, int &pos) const; static const int MaxAddressLength = 35; -signals: - -public slots: - }; #endif // BITCOINADDRESSVALIDATOR_H diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 9514ec8..b12e296 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -1,18 +1,14 @@ #include "bitcoinamountfield.h" + #include "qvaluecombobox.h" #include "bitcoinunits.h" - #include "guiconstants.h" -#include -#include -#include #include #include #include -#include #include -#include +#include // for qPow() BitcoinAmountField::BitcoinAmountField(QWidget *parent): QWidget(parent), amount(0), currentUnit(-1) @@ -102,7 +98,7 @@ bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event) { // Translate a comma into a period QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count()); - qApp->sendEvent(object, &periodKeyEvent); + QApplication::sendEvent(object, &periodKeyEvent); return true; } } @@ -149,6 +145,11 @@ void BitcoinAmountField::unitChanged(int idx) amount->setDecimals(BitcoinUnits::decimals(currentUnit)); amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals())); + if(currentUnit == BitcoinUnits::uBTC) + amount->setSingleStep(0.01); + else + amount->setSingleStep(0.001); + if(valid) { // If value was valid, re-place it in the widget with the new unit diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index ead8bdb..dacbb39 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -1,5 +1,5 @@ -#ifndef BITCOINFIELD_H -#define BITCOINFIELD_H +#ifndef BITCOINAMOUNTFIELD_H +#define BITCOINAMOUNTFIELD_H #include @@ -13,7 +13,9 @@ QT_END_NAMESPACE class BitcoinAmountField: public QWidget { Q_OBJECT + Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true) + public: explicit BitcoinAmountField(QWidget *parent = 0); @@ -31,7 +33,7 @@ public: /** Make field empty and ready for new input. */ void clear(); - /** Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907), + /** Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907), in these cases we have to set it up manually. */ QWidget *setupTabChain(QWidget *prev); @@ -40,7 +42,7 @@ signals: void textChanged(); protected: - /** Intercept focus-in event and ',' keypresses */ + /** Intercept focus-in event and ',' key presses */ bool eventFilter(QObject *object, QEvent *event); private: @@ -56,5 +58,4 @@ private slots: }; - -#endif // BITCOINFIELD_H +#endif // BITCOINAMOUNTFIELD_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 16aa068..c3e8ed4 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -3,84 +3,89 @@ * * W.J. van der Laan 2011-2012 * The Bitcoin Developers 2011-2012 - * The CasinoCoin Developers 201-2013 */ + +#include + #include "bitcoingui.h" + #include "transactiontablemodel.h" -#include "addressbookpage.h" -#include "sendcoinsdialog.h" -#include "signverifymessagedialog.h" #include "optionsdialog.h" #include "aboutdialog.h" #include "clientmodel.h" #include "walletmodel.h" -#include "editaddressdialog.h" +#include "walletframe.h" #include "optionsmodel.h" #include "transactiondescdialog.h" -#include "addresstablemodel.h" -#include "transactionview.h" -#include "overviewpage.h" #include "bitcoinunits.h" #include "guiconstants.h" -#include "askpassphrasedialog.h" #include "notificator.h" #include "guiutil.h" #include "rpcconsole.h" +#include "ui_interface.h" +#include "wallet.h" +#include "init.h" -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC #include "macdockiconhandler.h" #endif -#include -#include #include #include #include -#include #include #include #include #include -#include -#include -#include #include #include #include #include #include -#include -#include #include #include +#if QT_VERSION < 0x050000 #include +#endif +#include +#include +#include +#include +#include #include -BitcoinGUI::BitcoinGUI(QWidget *parent): +const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; + +BitcoinGUI::BitcoinGUI(QWidget *parent) : QMainWindow(parent), clientModel(0), - walletModel(0), encryptWalletAction(0), changePassphraseAction(0), aboutQtAction(0), trayIcon(0), notificator(0), - rpcConsole(0) + rpcConsole(0), + prevBlocks(0) { - resize(850, 550); + restoreWindowGeometry(); setWindowTitle(tr("CasinoCoin") + " - " + tr("Wallet")); -#ifndef Q_WS_MAC - qApp->setWindowIcon(QIcon(":icons/bitcoin")); +#ifndef Q_OS_MAC + QApplication::setWindowIcon(QIcon(":icons/bitcoin")); setWindowIcon(QIcon(":icons/bitcoin")); #else setUnifiedTitleAndToolBarOnMac(true); QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); #endif + // Create wallet frame and make it the central widget + walletFrame = new WalletFrame(this); + setCentralWidget(walletFrame); + // Accept D&D of URIs setAcceptDrops(true); // Create actions for the toolbar, menu bar and tray/dock icon + // Needs walletFrame to be initialized createActions(); // Create application menu bar @@ -89,45 +94,17 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): // Create the toolbars createToolBars(); - // Create the tray icon (or setup the dock icon) + // Create system tray icon and notification createTrayIcon(); - // Create tabs - overviewPage = new OverviewPage(); - - transactionsPage = new QWidget(this); - QVBoxLayout *vbox = new QVBoxLayout(); - transactionView = new TransactionView(this); - vbox->addWidget(transactionView); - transactionsPage->setLayout(vbox); - - addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); - - receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); - - sendCoinsPage = new SendCoinsDialog(this); - - signVerifyMessageDialog = new SignVerifyMessageDialog(this); - - centralWidget = new QStackedWidget(this); - centralWidget->addWidget(overviewPage); - centralWidget->addWidget(transactionsPage); - centralWidget->addWidget(addressBookPage); - centralWidget->addWidget(receiveCoinsPage); - centralWidget->addWidget(sendCoinsPage); -#ifdef FIRST_CLASS_MESSAGING - centralWidget->addWidget(signVerifyMessageDialog); -#endif - setCentralWidget(centralWidget); - // Create status bar statusBar(); // Status bar notification icons QFrame *frameBlocks = new QFrame(); frameBlocks->setContentsMargins(0,0,0,0); - frameBlocks->setMinimumWidth(73); - frameBlocks->setMaximumWidth(73); + frameBlocks->setMinimumWidth(56); + frameBlocks->setMaximumWidth(56); QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks); frameBlocksLayout->setContentsMargins(3,0,3,0); frameBlocksLayout->setSpacing(3); @@ -149,36 +126,39 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): progressBar->setAlignment(Qt::AlignCenter); progressBar->setVisible(false); + // Override style sheet for progress bar for styles that have a segmented progress bar, + // as they make the text unreadable (workaround for issue #1071) + // See https://qt-project.org/doc/qt-4.8/gallery.html + QString curStyle = QApplication::style()->metaObject()->className(); + if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle") + { + progressBar->setStyleSheet("QProgressBar { background-color: #e8e8e8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: 7px; margin: 0px; }"); + } + statusBar()->addWidget(progressBarLabel); statusBar()->addWidget(progressBar); statusBar()->addPermanentWidget(frameBlocks); syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this); - // Clicking on a transaction on the overview page simply sends you to transaction history page - connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage())); - connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); - - // Doubleclicking on a transaction on the transaction history page shows details - connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); - rpcConsole = new RPCConsole(this); connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show())); - // Clicking on "Verify Message" in the address book sends you to the verify message tab - connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString))); - // Clicking on "Sign Message" in the receive coins page sends you to the sign message tab - connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); + // Install event filter to be able to catch status tip events (QEvent::StatusTip) + this->installEventFilter(this); - gotoOverviewPage(); + // Initially wallet actions should be disabled + setWalletActionsEnabled(false); } BitcoinGUI::~BitcoinGUI() { + saveWindowGeometry(); if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) trayIcon->hide(); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC delete appMenuBar; + MacDockIconHandler::instance()->setMainWindow(NULL); #endif } @@ -187,110 +167,97 @@ void BitcoinGUI::createActions() QActionGroup *tabGroup = new QActionGroup(this); overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this); - overviewAction->setToolTip(tr("Show general overview of wallet")); + overviewAction->setStatusTip(tr("Show general overview of wallet")); + overviewAction->setToolTip(overviewAction->statusTip()); overviewAction->setCheckable(true); overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1)); tabGroup->addAction(overviewAction); - historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); - historyAction->setToolTip(tr("Browse transaction history")); - historyAction->setCheckable(true); - historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); - tabGroup->addAction(historyAction); - - addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this); - addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels")); - addressBookAction->setCheckable(true); - addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); - tabGroup->addAction(addressBookAction); - - receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this); - receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments")); - receiveCoinsAction->setCheckable(true); - receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); - tabGroup->addAction(receiveCoinsAction); - - sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this); - sendCoinsAction->setToolTip(tr("Send coins to a CasinoCoin address")); + sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send"), this); + sendCoinsAction->setStatusTip(tr("Send coins to a CasinoCoin address")); + sendCoinsAction->setToolTip(sendCoinsAction->statusTip()); sendCoinsAction->setCheckable(true); sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); tabGroup->addAction(sendCoinsAction); - signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this); - signMessageAction->setToolTip(tr("Sign a message to prove you own a Bitcoin address")); - tabGroup->addAction(signMessageAction); + receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive"), this); + receiveCoinsAction->setStatusTip(tr("Show the list of addresses for receiving payments")); + receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); + receiveCoinsAction->setCheckable(true); + receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); + tabGroup->addAction(receiveCoinsAction); - verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this); - verifyMessageAction->setToolTip(tr("Verify a message to ensure it was signed with a specified Bitcoin address")); - tabGroup->addAction(verifyMessageAction); + historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); + historyAction->setStatusTip(tr("Browse transaction history")); + historyAction->setToolTip(historyAction->statusTip()); + historyAction->setCheckable(true); + historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); + tabGroup->addAction(historyAction); -#ifdef FIRST_CLASS_MESSAGING - firstClassMessagingAction = new QAction(QIcon(":/icons/edit"), tr("S&ignatures"), this); - firstClassMessagingAction->setToolTip(signMessageAction->toolTip() + QString(". / ") + verifyMessageAction->toolTip() + QString(".")); - firstClassMessagingAction->setCheckable(true); - tabGroup->addAction(firstClassMessagingAction); -#endif + addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Addresses"), this); + addressBookAction->setStatusTip(tr("Edit the list of stored addresses and labels")); + addressBookAction->setToolTip(addressBookAction->statusTip()); + addressBookAction->setCheckable(true); + addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); + tabGroup->addAction(addressBookAction); connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); + connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage())); - connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); - connect(signMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); - connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); -#ifdef FIRST_CLASS_MESSAGING - connect(firstClassMessagingAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - // Always start with the sign message tab for FIRST_CLASS_MESSAGING - connect(firstClassMessagingAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); -#endif quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); - quitAction->setToolTip(tr("Quit application")); + quitAction->setStatusTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); quitAction->setMenuRole(QAction::QuitRole); aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About CasinoCoin"), this); - aboutAction->setToolTip(tr("Show information about CasinoCoin")); + aboutAction->setStatusTip(tr("Show information about CasinoCoin")); aboutAction->setMenuRole(QAction::AboutRole); - aboutQtAction = new QAction(tr("About &Qt"), this); - aboutQtAction->setToolTip(tr("Show information about Qt")); + aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); + aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); - optionsAction->setToolTip(tr("Modify configuration options for CasinoCoin")); + optionsAction->setStatusTip(tr("Modify configuration options for CasinoCoin")); optionsAction->setMenuRole(QAction::PreferencesRole); - toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("Show/Hide &CasinoCoin"), this); - toggleHideAction->setToolTip(tr("Show or hide the CasinoCoin window")); - exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); - exportAction->setToolTip(tr("Export the data in the current tab to a file")); + toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this); + toggleHideAction->setStatusTip(tr("Show or hide the main Window")); + encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); - encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet")); + encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet")); encryptWalletAction->setCheckable(true); backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this); - backupWalletAction->setToolTip(tr("Backup wallet to another location")); + backupWalletAction->setStatusTip(tr("Backup wallet to another location")); changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this); - changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption")); + changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption")); + signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this); + signMessageAction->setStatusTip(tr("Sign messages with your CasinoCoin addresses to prove you own them")); + verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this); + verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified CasinoCoin addresses")); + openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this); - openRPCConsoleAction->setToolTip(tr("Open debugging and diagnostic console")); + openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console")); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); - connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool))); - connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet())); - connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase())); + connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); + connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet())); + connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase())); + connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); + connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); } void BitcoinGUI::createMenuBar() { -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC // Create a decoupled menu bar on Mac which stays even if the window is closed appMenuBar = new QMenuBar(); #else @@ -301,11 +268,8 @@ void BitcoinGUI::createMenuBar() // Configure the menus QMenu *file = appMenuBar->addMenu(tr("&File")); file->addAction(backupWalletAction); - file->addAction(exportAction); -#ifndef FIRST_CLASS_MESSAGING file->addAction(signMessageAction); file->addAction(verifyMessageAction); -#endif file->addSeparator(); file->addAction(quitAction); @@ -331,13 +295,6 @@ void BitcoinGUI::createToolBars() toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); toolbar->addAction(addressBookAction); -#ifdef FIRST_CLASS_MESSAGING - toolbar->addAction(firstClassMessagingAction); -#endif - - QToolBar *toolbar2 = addToolBar(tr("Actions toolbar")); - toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - toolbar2->addAction(exportAction); } void BitcoinGUI::setClientModel(ClientModel *clientModel) @@ -349,22 +306,27 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) if(clientModel->isTestNet()) { setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]")); -#ifndef Q_WS_MAC - qApp->setWindowIcon(QIcon(":icons/bitcoin_testnet")); +#ifndef Q_OS_MAC + QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet")); setWindowIcon(QIcon(":icons/bitcoin_testnet")); #else MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); #endif if(trayIcon) { - trayIcon->setToolTip(tr("CasinoCoin client") + QString(" ") + tr("[testnet]")); + // Just attach " [testnet]" to the existing tooltip + trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]")); trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); - toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); } + toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); aboutAction->setIcon(QIcon(":/icons/toolbar_testnet")); } + // 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))); @@ -372,59 +334,75 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers()); connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); - // Report errors from network/worker thread - connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); + // Receive and report messages from network/worker thread + connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); rpcConsole->setClientModel(clientModel); - addressBookPage->setOptionsModel(clientModel->getOptionsModel()); - receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); + walletFrame->setClientModel(clientModel); } } -void BitcoinGUI::setWalletModel(WalletModel *walletModel) +bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel) { - this->walletModel = walletModel; - if(walletModel) - { - // Report errors from wallet thread - connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); + setWalletActionsEnabled(true); + return walletFrame->addWallet(name, walletModel); +} - // Put transaction list in tabs - transactionView->setModel(walletModel); +bool BitcoinGUI::setCurrentWallet(const QString& name) +{ + return walletFrame->setCurrentWallet(name); +} - overviewPage->setModel(walletModel); - addressBookPage->setModel(walletModel->getAddressTableModel()); - receiveCoinsPage->setModel(walletModel->getAddressTableModel()); - sendCoinsPage->setModel(walletModel); - signVerifyMessageDialog->setModel(walletModel); +void BitcoinGUI::removeAllWallets() +{ + setWalletActionsEnabled(false); + walletFrame->removeAllWallets(); +} - setEncryptionStatus(walletModel->getEncryptionStatus()); - connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int))); - - // Balloon popup for new transaction - connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(incomingTransaction(QModelIndex,int,int))); - - // Ask for passphrase if needed - connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); - } +void BitcoinGUI::setWalletActionsEnabled(bool enabled) +{ + overviewAction->setEnabled(enabled); + sendCoinsAction->setEnabled(enabled); + receiveCoinsAction->setEnabled(enabled); + historyAction->setEnabled(enabled); + encryptWalletAction->setEnabled(enabled); + backupWalletAction->setEnabled(enabled); + changePassphraseAction->setEnabled(enabled); + signMessageAction->setEnabled(enabled); + verifyMessageAction->setEnabled(enabled); + addressBookAction->setEnabled(enabled); } void BitcoinGUI::createTrayIcon() { - QMenu *trayIconMenu; -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); - trayIconMenu = new QMenu(this); - trayIcon->setContextMenu(trayIconMenu); + trayIcon->setToolTip(tr("CasinoCoin client")); trayIcon->setIcon(QIcon(":/icons/toolbar")); + trayIcon->show(); +#endif + + notificator = new Notificator(QApplication::applicationName(), trayIcon); +} + +void BitcoinGUI::createTrayIconMenu() +{ + QMenu *trayIconMenu; +#ifndef Q_OS_MAC + // return if trayIcon is unset (only on non-Mac OSes) + if (!trayIcon) + return; + + trayIconMenu = new QMenu(this); + trayIcon->setContextMenu(trayIconMenu); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); - trayIcon->show(); #else // Note: On Mac, the dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); + dockIconHandler->setMainWindow((QMainWindow *)this); trayIconMenu = dockIconHandler->dockMenu(); #endif @@ -433,33 +411,51 @@ void BitcoinGUI::createTrayIcon() trayIconMenu->addSeparator(); trayIconMenu->addAction(sendCoinsAction); trayIconMenu->addAction(receiveCoinsAction); -#ifndef FIRST_CLASS_MESSAGING trayIconMenu->addSeparator(); -#endif trayIconMenu->addAction(signMessageAction); trayIconMenu->addAction(verifyMessageAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(optionsAction); trayIconMenu->addAction(openRPCConsoleAction); -#ifndef Q_WS_MAC // This is built-in on Mac +#ifndef Q_OS_MAC // This is built-in on Mac trayIconMenu->addSeparator(); trayIconMenu->addAction(quitAction); #endif - - notificator = new Notificator(qApp->applicationName(), trayIcon); } -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { if(reason == QSystemTrayIcon::Trigger) { - // Click on system tray icon triggers "show/hide CasinoCoin" + // Click on system tray icon triggers show/hide of the main window toggleHideAction->trigger(); } } #endif +void BitcoinGUI::saveWindowGeometry() +{ + QSettings settings; + settings.setValue("nWindowPos", pos()); + settings.setValue("nWindowSize", size()); +} + +void BitcoinGUI::restoreWindowGeometry() +{ + QSettings settings; + QPoint pos = settings.value("nWindowPos").toPoint(); + QSize size = settings.value("nWindowSize", QSize(850, 550)).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); + } + resize(size); + move(pos); +} + void BitcoinGUI::optionsClicked() { if(!clientModel || !clientModel->getOptionsModel()) @@ -476,6 +472,41 @@ void BitcoinGUI::aboutClicked() dlg.exec(); } +void BitcoinGUI::gotoOverviewPage() +{ + if (walletFrame) walletFrame->gotoOverviewPage(); +} + +void BitcoinGUI::gotoHistoryPage() +{ + if (walletFrame) walletFrame->gotoHistoryPage(); +} + +void BitcoinGUI::gotoAddressBookPage() +{ + if (walletFrame) walletFrame->gotoAddressBookPage(); +} + +void BitcoinGUI::gotoReceiveCoinsPage() +{ + if (walletFrame) walletFrame->gotoReceiveCoinsPage(); +} + +void BitcoinGUI::gotoSendCoinsPage(QString addr) +{ + if (walletFrame) walletFrame->gotoSendCoinsPage(addr); +} + +void BitcoinGUI::gotoSignMessageTab(QString addr) +{ + if (walletFrame) walletFrame->gotoSignMessageTab(addr); +} + +void BitcoinGUI::gotoVerifyMessageTab(QString addr) +{ + if (walletFrame) walletFrame->gotoVerifyMessageTab(addr); +} + void BitcoinGUI::setNumConnections(int count) { QString icon; @@ -493,79 +524,40 @@ void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) { - // don't show / hide progressBar and it's label if we have no connection(s) to the network - if (!clientModel || clientModel->getNumConnections() == 0) - { - progressBarLabel->setVisible(false); - progressBar->setVisible(false); + // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text) + statusBar()->clearMessage(); - return; + // Acquire current block source + enum BlockSource blockSource = clientModel->getBlockSource(); + switch (blockSource) { + case BLOCK_SOURCE_NETWORK: + progressBarLabel->setText(tr("Synchronizing with network...")); + break; + case BLOCK_SOURCE_DISK: + progressBarLabel->setText(tr("Importing blocks from disk...")); + break; + case BLOCK_SOURCE_REINDEX: + progressBarLabel->setText(tr("Reindexing blocks on disk...")); + break; + case BLOCK_SOURCE_NONE: + // Case: not Importing, not Reindexing and no network connection + progressBarLabel->setText(tr("No block source available...")); + break; } QString tooltip; + QDateTime lastBlockDate = clientModel->getLastBlockDate(); + QDateTime currentDate = QDateTime::currentDateTime(); + int secs = lastBlockDate.secsTo(currentDate); + if(count < nTotalBlocks) { - int nRemainingBlocks = nTotalBlocks - count; - float nPercentageDone = count / (nTotalBlocks * 0.01f); - - if (clientModel->getStatusBarWarnings() == "") - { - progressBarLabel->setText(tr("Synchronizing with network...")); - progressBarLabel->setVisible(true); - progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks)); - progressBar->setMaximum(nTotalBlocks); - progressBar->setValue(count); - progressBar->setVisible(true); - } - else - { - progressBarLabel->setText(clientModel->getStatusBarWarnings()); - progressBarLabel->setVisible(true); - progressBar->setVisible(false); - } - tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2); + tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks); } else { - if (clientModel->getStatusBarWarnings() == "") - progressBarLabel->setVisible(false); - else - { - progressBarLabel->setText(clientModel->getStatusBarWarnings()); - progressBarLabel->setVisible(true); - } - progressBar->setVisible(false); - tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count); - } - - tooltip = tr("Current difficulty is %1.").arg(clientModel->GetDifficulty()) + QString("
") + tooltip; - - QDateTime now = QDateTime::currentDateTime(); - QDateTime lastBlockDate = clientModel->getLastBlockDate(); - int secs = lastBlockDate.secsTo(now); - QString text; - - // Represent time from last generated block in human readable text - if(secs <= 0) - { - // Fully up to date. Leave text empty. - } - else if(secs < 60) - { - text = tr("%n second(s) ago","",secs); - } - else if(secs < 60*60) - { - text = tr("%n minute(s) ago","",secs/60); - } - else if(secs < 24*60*60) - { - text = tr("%n hour(s) ago","",secs/(60*60)); - } - else - { - text = tr("%n day(s) ago","",secs/(60*60*24)); + tooltip = tr("Processed %1 blocks of transaction history.").arg(count); } // Set icon state: spinning if catching up, tick otherwise @@ -574,21 +566,46 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) tooltip = tr("Up to date") + QString(".
") + tooltip; labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); - overviewPage->showOutOfSyncWarning(false); + walletFrame->showOutOfSyncWarning(false); + + progressBarLabel->setVisible(false); + progressBar->setVisible(false); } else { + // Represent time from last generated block in human readable text + QString timeBehindText; + if(secs < 48*60*60) + { + timeBehindText = tr("%n hour(s)","",secs/(60*60)); + } + else if(secs < 14*24*60*60) + { + timeBehindText = tr("%n day(s)","",secs/(24*60*60)); + } + else + { + timeBehindText = tr("%n week(s)","",secs/(7*24*60*60)); + } + + progressBarLabel->setVisible(true); + progressBar->setFormat(tr("%1 behind").arg(timeBehindText)); + progressBar->setMaximum(1000000000); + progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5); + progressBar->setVisible(true); + tooltip = tr("Catching up...") + QString("
") + tooltip; labelBlocksIcon->setMovie(syncIconMovie); - syncIconMovie->start(); + if(count != prevBlocks) + syncIconMovie->jumpToNextFrame(); + prevBlocks = count; - overviewPage->showOutOfSyncWarning(true); - } + walletFrame->showOutOfSyncWarning(true); - if(!text.isEmpty()) - { tooltip += QString("
"); - tooltip += tr("Last received block was generated %1.").arg(text); + tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText); + tooltip += QString("
"); + tooltip += tr("Transactions after this will not yet be visible."); } // Don't word-wrap this (fixed-width) tooltip @@ -599,21 +616,61 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) progressBar->setToolTip(tooltip); } -void BitcoinGUI::error(const QString &title, const QString &message, bool modal) +void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret) { - // Report errors from network/worker thread - if(modal) - { - QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok); - } else { - notificator->notify(Notificator::Critical, title, message); + QString strTitle = tr("CasinoCoin"); // default title + // Default to information icon + int nMBoxIcon = QMessageBox::Information; + int nNotifyIcon = Notificator::Information; + + // Override title based on style + QString msgType; + switch (style) { + case CClientUIInterface::MSG_ERROR: + msgType = tr("Error"); + break; + case CClientUIInterface::MSG_WARNING: + msgType = tr("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + msgType = tr("Information"); + break; + default: + msgType = title; // Use supplied title } + if (!msgType.isEmpty()) + strTitle += " - " + msgType; + + // Check for error/warning icon + if (style & CClientUIInterface::ICON_ERROR) { + nMBoxIcon = QMessageBox::Critical; + nNotifyIcon = Notificator::Critical; + } + else if (style & CClientUIInterface::ICON_WARNING) { + nMBoxIcon = QMessageBox::Warning; + nNotifyIcon = Notificator::Warning; + } + + // Display message + if (style & CClientUIInterface::MODAL) { + // Check for buttons, use OK as default, if none was supplied + QMessageBox::StandardButton buttons; + if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK))) + buttons = QMessageBox::Ok; + + QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons); + int r = mBox.exec(); + if (ret != NULL) + *ret = r == QMessageBox::Ok; + } + else + notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message); } void BitcoinGUI::changeEvent(QEvent *e) { QMainWindow::changeEvent(e); -#ifndef Q_WS_MAC // Ignored on Mac +#ifndef Q_OS_MAC // Ignored on Mac if(e->type() == QEvent::WindowStateChange) { if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray()) @@ -633,11 +690,11 @@ void BitcoinGUI::closeEvent(QCloseEvent *event) { if(clientModel) { -#ifndef Q_WS_MAC // Ignored on Mac +#ifndef Q_OS_MAC // Ignored on Mac if(!clientModel->getOptionsModel()->getMinimizeToTray() && !clientModel->getOptionsModel()->getMinimizeOnClose()) { - qApp->quit(); + QApplication::quit(); } #endif } @@ -646,136 +703,27 @@ void BitcoinGUI::closeEvent(QCloseEvent *event) void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) { - QString strMessage = - tr("This transaction is over the size limit. You can still send it for a fee of %1, " - "which goes to the nodes that process your transaction and helps to support the network. " - "Do you want to pay the fee?").arg( - BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired)); + QString strMessage = tr("This transaction is over the size limit. You can still send it for a fee of %1, " + "which goes to the nodes that process your transaction and helps to support the network. " + "Do you want to pay the fee?").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired)); QMessageBox::StandardButton retval = QMessageBox::question( this, tr("Confirm transaction fee"), strMessage, QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes); *payFee = (retval == QMessageBox::Yes); } -void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end) +void BitcoinGUI::incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address) { - if(!walletModel || !clientModel) - return; - TransactionTableModel *ttm = walletModel->getTransactionTableModel(); - qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent) - .data(Qt::EditRole).toULongLong(); - if(!clientModel->inInitialBlockDownload()) - { - // On new transaction, make an info balloon - // Unless the initial block download is in progress, to prevent balloon-spam - QString date = ttm->index(start, TransactionTableModel::Date, parent) - .data().toString(); - QString type = ttm->index(start, TransactionTableModel::Type, parent) - .data().toString(); - QString address = ttm->index(start, TransactionTableModel::ToAddress, parent) - .data().toString(); - QIcon icon = qvariant_cast(ttm->index(start, - TransactionTableModel::ToAddress, parent) - .data(Qt::DecorationRole)); - - notificator->notify(Notificator::Information, - (amount)<0 ? tr("Sent transaction") : - tr("Incoming transaction"), - tr("Date: %1\n" - "Amount: %2\n" - "Type: %3\n" - "Address: %4\n") - .arg(date) - .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true)) - .arg(type) - .arg(address), icon); - } -} - -void BitcoinGUI::gotoOverviewPage() -{ - overviewAction->setChecked(true); - centralWidget->setCurrentWidget(overviewPage); - - exportAction->setEnabled(false); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); -} - -void BitcoinGUI::gotoHistoryPage() -{ - historyAction->setChecked(true); - centralWidget->setCurrentWidget(transactionsPage); - - exportAction->setEnabled(true); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); - connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked())); -} - -void BitcoinGUI::gotoAddressBookPage() -{ - addressBookAction->setChecked(true); - centralWidget->setCurrentWidget(addressBookPage); - - exportAction->setEnabled(true); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); - connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked())); -} - -void BitcoinGUI::gotoReceiveCoinsPage() -{ - receiveCoinsAction->setChecked(true); - centralWidget->setCurrentWidget(receiveCoinsPage); - - exportAction->setEnabled(true); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); - connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked())); -} - -void BitcoinGUI::gotoSendCoinsPage() -{ - sendCoinsAction->setChecked(true); - centralWidget->setCurrentWidget(sendCoinsPage); - - exportAction->setEnabled(false); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); -} - -void BitcoinGUI::gotoSignMessageTab(QString addr) -{ -#ifdef FIRST_CLASS_MESSAGING - firstClassMessagingAction->setChecked(true); - centralWidget->setCurrentWidget(signVerifyMessageDialog); - - exportAction->setEnabled(false); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); - - signVerifyMessageDialog->showTab_SM(false); -#else - // call show() in showTab_SM() - signVerifyMessageDialog->showTab_SM(true); -#endif - - if(!addr.isEmpty()) - signVerifyMessageDialog->setAddress_SM(addr); -} - -void BitcoinGUI::gotoVerifyMessageTab(QString addr) -{ -#ifdef FIRST_CLASS_MESSAGING - firstClassMessagingAction->setChecked(true); - centralWidget->setCurrentWidget(signVerifyMessageDialog); - - exportAction->setEnabled(false); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); - - signVerifyMessageDialog->showTab_VM(false); -#else - // call show() in showTab_VM() - signVerifyMessageDialog->showTab_VM(true); -#endif - - if(!addr.isEmpty()) - signVerifyMessageDialog->setAddress_VM(addr); + // On new transaction, make an info balloon + message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"), + tr("Date: %1\n" + "Amount: %2\n" + "Type: %3\n" + "Address: %4\n") + .arg(date) + .arg(BitcoinUnits::formatWithUnit(unit, amount, true)) + .arg(type) + .arg(address), CClientUIInterface::MSG_INFORMATION); } void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event) @@ -793,30 +741,39 @@ void BitcoinGUI::dropEvent(QDropEvent *event) QList uris = event->mimeData()->urls(); foreach(const QUrl &uri, uris) { - if (sendCoinsPage->handleURI(uri.toString())) + if (walletFrame->handleURI(uri.toString())) nValidUrisFound++; } // if valid URIs were found if (nValidUrisFound) - gotoSendCoinsPage(); + walletFrame->gotoSendCoinsPage(); else - notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters.")); + message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters."), + CClientUIInterface::ICON_WARNING); } event->acceptProposedAction(); } +bool BitcoinGUI::eventFilter(QObject *object, QEvent *event) +{ + // Catch status tip events + if (event->type() == QEvent::StatusTip) + { + // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff + if (progressBarLabel->isVisible() || progressBar->isVisible()) + return true; + } + return QMainWindow::eventFilter(object, event); +} + void BitcoinGUI::handleURI(QString strURI) { // URI has to be valid - if (sendCoinsPage->handleURI(strURI)) - { - showNormalIfMinimized(); - gotoSendCoinsPage(); - } - else - notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters.")); + if (!walletFrame->handleURI(strURI)) + message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters."), + CClientUIInterface::ICON_WARNING); } void BitcoinGUI::setEncryptionStatus(int status) @@ -848,49 +805,6 @@ void BitcoinGUI::setEncryptionStatus(int status) } } -void BitcoinGUI::encryptWallet(bool status) -{ - if(!walletModel) - return; - AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt: - AskPassphraseDialog::Decrypt, this); - dlg.setModel(walletModel); - dlg.exec(); - - setEncryptionStatus(walletModel->getEncryptionStatus()); -} - -void BitcoinGUI::backupWallet() -{ - QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); - QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); - if(!filename.isEmpty()) { - if(!walletModel->backupWallet(filename)) { - QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location.")); - } - } -} - -void BitcoinGUI::changePassphrase() -{ - AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); - dlg.setModel(walletModel); - dlg.exec(); -} - -void BitcoinGUI::unlockWallet() -{ - if(!walletModel) - return; - // Unlock wallet when requested by wallet model - if(walletModel->getEncryptionStatus() == WalletModel::Locked) - { - AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this); - dlg.setModel(walletModel); - dlg.exec(); - } -} - void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) { // activateWindow() (sometimes) helps with keyboard focus on Windows @@ -917,3 +831,9 @@ void BitcoinGUI::toggleHidden() { showNormalIfMinimized(true); } + +void BitcoinGUI::detectShutdown() +{ + if (ShutdownRequested()) + QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); +} diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 9e0cd0c..5656af4 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -3,10 +3,14 @@ #include #include +#include class TransactionTableModel; +class WalletFrame; +class WalletView; class ClientModel; class WalletModel; +class WalletStack; class TransactionView; class OverviewPage; class AddressBookPage; @@ -15,15 +19,17 @@ class SignVerifyMessageDialog; class Notificator; class RPCConsole; +class CWallet; + QT_BEGIN_NAMESPACE class QLabel; -class QLineEdit; -class QTableView; -class QAbstractItemModel; class QModelIndex; class QProgressBar; class QStackedWidget; class QUrl; +class QListWidget; +class QPushButton; +class QAction; QT_END_NAMESPACE /** @@ -33,7 +39,10 @@ QT_END_NAMESPACE class BitcoinGUI : public QMainWindow { Q_OBJECT + public: + static const QString DEFAULT_WALLET; + explicit BitcoinGUI(QWidget *parent = 0); ~BitcoinGUI(); @@ -45,26 +54,30 @@ public: The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. */ - void setWalletModel(WalletModel *walletModel); + + bool addWallet(const QString& name, WalletModel *walletModel); + bool setCurrentWallet(const QString& name); + + void removeAllWallets(); + + /** Used by WalletView to allow access to needed QActions */ + // Todo: Use Qt signals for these + QAction * getOverviewAction() { return overviewAction; } + QAction * getHistoryAction() { return historyAction; } + QAction * getAddressBookAction() { return addressBookAction; } + QAction * getReceiveCoinsAction() { return receiveCoinsAction; } + QAction * getSendCoinsAction() { return sendCoinsAction; } protected: void changeEvent(QEvent *e); void closeEvent(QCloseEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); + bool eventFilter(QObject *object, QEvent *event); private: ClientModel *clientModel; - WalletModel *walletModel; - - QStackedWidget *centralWidget; - - OverviewPage *overviewPage; - QWidget *transactionsPage; - AddressBookPage *addressBookPage; - AddressBookPage *receiveCoinsPage; - SendCoinsDialog *sendCoinsPage; - SignVerifyMessageDialog *signVerifyMessageDialog; + WalletFrame *walletFrame; QLabel *labelEncryptionIcon; QLabel *labelConnectionsIcon; @@ -80,12 +93,10 @@ private: QAction *addressBookAction; QAction *signMessageAction; QAction *verifyMessageAction; - QAction *firstClassMessagingAction; QAction *aboutAction; QAction *receiveCoinsAction; QAction *optionsAction; QAction *toggleHideAction; - QAction *exportAction; QAction *encryptWalletAction; QAction *backupWalletAction; QAction *changePassphraseAction; @@ -98,33 +109,49 @@ private: RPCConsole *rpcConsole; QMovie *syncIconMovie; + /** Keep track of previous number of blocks, to detect progress */ + int prevBlocks; /** Create the main UI actions. */ void createActions(); - /** Create the menu bar and submenus. */ + /** Create the menu bar and sub-menus. */ void createMenuBar(); /** Create the toolbars */ void createToolBars(); - /** Create system tray (notification) icon */ + /** Create system tray icon and notification */ void createTrayIcon(); + /** Create system tray menu (or setup the dock menu) */ + void createTrayIconMenu(); + /** Save window size and position */ + void saveWindowGeometry(); + /** Restore window size and position */ + void restoreWindowGeometry(); + /** Enable or disable all wallet-related actions */ + void setWalletActionsEnabled(bool enabled); public slots: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks shown in the UI */ - void setNumBlocks(int count, int countOfPeers); + void setNumBlocks(int count, int nTotalBlocks); /** Set the encryption status as shown in the UI. @param[in] status current encryption status @see WalletModel::EncryptionStatus */ void setEncryptionStatus(int status); - /** Notify the user of an error in the network or transaction handling code. */ - void error(const QString &title, const QString &message, bool modal); + /** Notify the user of an event from the core network or transaction handling code. + @param[in] title the message box / notification title + @param[in] message the displayed text + @param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes) + @see CClientUIInterface::MessageBoxFlags + @param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only) + */ + void message(const QString &title, const QString &message, unsigned int style, bool *ret = NULL); /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. - http://bugreports.qt.nokia.com/browse/QTBUG-10440 + https://bugreports.qt-project.org/browse/QTBUG-10440 @param[in] nFeeRequired the required fee @param[out] payFee true to pay the fee, false to not pay the fee @@ -132,6 +159,9 @@ public slots: void askFee(qint64 nFeeRequired, bool *payFee); void handleURI(QString strURI); + /** Show incoming transaction notification for new transactions. */ + void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address); + private slots: /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -142,7 +172,7 @@ private slots: /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ - void gotoSendCoinsPage(); + void gotoSendCoinsPage(QString addr = ""); /** Show Sign/Verify Message dialog and switch to sign message tab */ void gotoSignMessageTab(QString addr = ""); @@ -153,28 +183,18 @@ private slots: void optionsClicked(); /** Show about dialog */ void aboutClicked(); -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC /** Handle tray icon clicked */ void trayIconActivated(QSystemTrayIcon::ActivationReason reason); #endif - /** Show incoming transaction notification for new transactions. - - The new items are those between start and end inclusive, under the given parent item. - */ - void incomingTransaction(const QModelIndex & parent, int start, int end); - /** Encrypt the wallet */ - void encryptWallet(bool status); - /** Backup the wallet */ - void backupWallet(); - /** Change encrypted wallet passphrase */ - void changePassphrase(); - /** Ask for pass phrase to unlock wallet temporarily */ - void unlockWallet(); /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ void showNormalIfMinimized(bool fToggleHidden = false); - /** simply calls showNormalIfMinimized(true) for use in SLOT() macro */ + /** Simply calls showNormalIfMinimized(true) for use in SLOT() macro */ void toggleHidden(); + + /** called by a timer to check if fRequestShutdown has been set **/ + void detectShutdown(); }; -#endif +#endif // BITCOINGUI_H diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 2fe9f8b..72311f6 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -8,129 +8,187 @@ static const char UNUSED *bitcoin_strings[] = { QT_TRANSLATE_NOOP("bitcoin-core", "" "%s, you must set a rpcpassword in the configuration file:\n" -" %s\n" +"%s\n" "It is recommended you use the following random password:\n" "rpcuser=casinocoinrpc\n" "rpcpassword=%s\n" "(you do not need to remember this password)\n" +"The username and password MUST NOT be the same.\n" "If the file does not exist, create it with owner-readable-only file " -"permissions.\n"), +"permissions.\n" +"It is also recommended to set alertnotify so you are notified of problems;\n" +"for example: alertnotify=echo %%s | mail -s \"CasinoCoin Alert\" admin@foo.com\n"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:" "@STRENGTH)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Cannot obtain a lock on data directory %s. CasinoCoin is probably already " +"An error occurred while setting up the RPC port %u for listening on IPv4: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"An error occurred while setting up the RPC port %u for listening on IPv6, " +"falling back to IPv4: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Bind to given address and always listen on it. Use [host]:port notation for " +"IPv6"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Cannot obtain a lock on data directory %s. CasinoCoin is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Detach block and address databases. Increases shutdown time (default: 0)"), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"Error: The transaction was rejected. This might happen if some of the coins " +"Error: The transaction was rejected! This might happen if some of the coins " "in your wallet were already spent, such as if you used a copy of wallet.dat " "and coins were spent in the copy but not marked as spent here."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: This transaction requires a transaction fee of at least %s because of " -"its amount, complexity, or use of recently received funds "), +"its amount, complexity, or use of recently received funds!"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Execute command when a relevant alert is received (%s in cmd is replaced by " +"message)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Execute command when a wallet transaction changes (%s in cmd is replaced by " +"TxID)"), 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", "" +"Listen for JSON-RPC connections on (default: 47970 or testnet: 17970)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Number of seconds to keep misbehaving peers from reconnecting (default: " "86400)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Set maximum size of high-priority/low-fee transactions in bytes (default: " +"27000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Set the number of script verification threads (up to 16, 0 = auto, <0 = " +"leave that many cores free, default: 0)"), +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", "" "Unable to bind to %s on this computer. CasinoCoin is probably already running."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: -paytxfee is set very high. This is the transaction fee you will " +"Warning: -paytxfee is set very high! This is the transaction fee you will " "pay if you send a transaction."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: Please check that your computer's date and time are correct. If " +"Warning: Displayed transactions may not be correct! You may need to upgrade, " +"or other nodes may need to upgrade."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: Please check that your computer's date and time are correct! If " "your clock is wrong CasinoCoin will not work properly."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: error reading wallet.dat! All keys read correctly, but transaction " +"data or address book entries might be missing or incorrect."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as " +"wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect " +"you should restore from a backup."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "You must set rpcpassword= in the configuration file:\n" "%s\n" "If the file does not exist, create it with owner-readable-only file " "permissions."), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"\n" -"SSL options: (see the Bitcoin Wiki for SSL setup instructions)"), 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", "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"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"), -QT_TRANSLATE_NOOP("bitcoin-core", "An error occured while setting up the RPC port %i for listening: %s"), -QT_TRANSLATE_NOOP("bitcoin-core", "Bind to given address. Use [host]:port notation for IPv6"), +QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), QT_TRANSLATE_NOOP("bitcoin-core", "CasinoCoin version"), -QT_TRANSLATE_NOOP("bitcoin-core", "CasinoCoin"), +QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), -QT_TRANSLATE_NOOP("bitcoin-core", "Cannot initialize keypool"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks proxy"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), +QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"), +QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error loading blkindex.dat"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environment %s!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of CasinoCoin"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: system error: "), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block info"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to sync block index"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block index"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block info"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write file info"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to coin database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write transaction index"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data"), QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"), QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1 unless -connect)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using internet relay chat (default: 0)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"), +QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"), -QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"), -QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-6, default: 1)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000?.dat file"), +QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 288, 0 = all)"), +QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-4, default: 3)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"), +QT_TRANSLATE_NOOP("bitcoin-core", "Information"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -tor address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -minrelaytxfee=: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -mintxfee=: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"), QT_TRANSLATE_NOOP("bitcoin-core", "List commands"), -QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on (default: 9332)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: 9333 or testnet: 19333)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: 47950 or testnet: 17950)"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."), QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."), QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Maintain a full transaction index (default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most connections to peers (default: 125)"), QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, *1000 bytes (default: 5000)"), QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, *1000 bytes (default: 1000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."), +QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: 1)"), QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network (IPv4, IPv6 or Tor)"), QT_TRANSLATE_NOOP("bitcoin-core", "Options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information. Implies all other -debug* options"), QT_TRANSLATE_NOOP("bitcoin-core", "Output extra network debugging information"), QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"), QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"), +QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild block chain index from current blk000??.dat files"), QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"), QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."), QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"), +QT_TRANSLATE_NOOP("bitcoin-core", "SSL options: (see the CasinoCoin Wiki for SSL setup instructions)"), QT_TRANSLATE_NOOP("bitcoin-core", "Select the version of socks proxy to use (4-5, default: 5)"), QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or casinocoind"), QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on (default: 127.0.0.1)"), QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"), QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"), -QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."), QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"), QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (default: 25)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Set database disk log size in megabytes (default: 100)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to (default: 100)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: 250000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: 0)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: 4)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: casinocoin.conf)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout (in milliseconds)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (default: 5000)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: casinocoind.pid)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"), +QT_TRANSLATE_NOOP("bitcoin-core", "System error: "), QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"), QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"), +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 too large"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), @@ -142,7 +200,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: QT_TRANSLATE_NOOP("bitcoin-core", "Use proxy to reach tor hidden services (default: same as -proxy)"), QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"), QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"), +QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."), QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart CasinoCoin to complete"), -QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low"), -QT_TRANSLATE_NOOP("bitcoin-core", "Warning: this version is obsolete, upgrade required"), +QT_TRANSLATE_NOOP("bitcoin-core", "Warning"), +QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"), +QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"), +QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"), }; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 9db1f53..fe5bc31 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -99,7 +99,7 @@ QString BitcoinUnits::format(int unit, qint64 n, bool fPlus) QString quotient_str = QString::number(quotient); QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0'); - // Right-trim excess 0's after the decimal point + // Right-trim excess zeros after the decimal point int nTrim = 0; for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i) ++nTrim; diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index 18fa36a..6e96cef 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -5,10 +5,12 @@ #include /** Bitcoin unit definitions. Encapsulates parsing and formatting - and serves as list model for dropdown selection boxes. + and serves as list model for drop-down selection boxes. */ class BitcoinUnits: public QAbstractListModel { + Q_OBJECT + public: explicit BitcoinUnits(QObject *parent); @@ -26,7 +28,7 @@ public: //! Unit conversion and formatting ///@{ - //! Get list of units, for dropdown box + //! Get list of units, for drop-down box static QList availableUnits(); //! Is unit ID valid? static bool valid(int unit); @@ -49,7 +51,7 @@ public: ///@} //! @name AbstractListModel implementation - //! List model for unit dropdown selection box. + //! List model for unit drop-down selection box. ///@{ enum RoleIndex { /** Unit identifier */ @@ -58,6 +60,7 @@ public: int rowCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; ///@} + private: QList unitlist; }; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index c86c9a6..e8d99a8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -1,11 +1,13 @@ #include "clientmodel.h" + #include "guiconstants.h" #include "optionsmodel.h" #include "addresstablemodel.h" #include "transactiontablemodel.h" +#include "alert.h" #include "main.h" -#include "init.h" // for pwalletMain +#include "checkpoints.h" #include "ui_interface.h" #include @@ -15,10 +17,10 @@ static const int64 nClientStartupTime = GetTime(); ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : QObject(parent), optionsModel(optionsModel), - cachedNumBlocks(0), cachedNumBlocksOfPeers(0), cachedHashrate(0), pollTimer(0) + cachedNumBlocks(0), cachedNumBlocksOfPeers(0), + cachedReindexing(0), cachedImporting(0), + numBlocksAtStartup(-1), pollTimer(0) { - numBlocksAtStartup = -1; - pollTimer = new QTimer(this); pollTimer->setInterval(MODEL_UPDATE_DELAY); pollTimer->start(); @@ -48,43 +50,19 @@ int ClientModel::getNumBlocksAtStartup() return numBlocksAtStartup; } -int ClientModel::getHashrate() const -{ - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (boost::int64_t)0; - return (boost::int64_t)dHashesPerSec; -} - -// CasinoCoin: copied from bitcoinrpc.cpp. -double ClientModel::GetDifficulty() const -{ - // Floating point number that is a multiple of the minimum difficulty, - // minimum difficulty = 1.0. - - if (pindexBest == NULL) - return 1.0; - int nShift = (pindexBest->nBits >> 24) & 0xff; - - double dDiff = - (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff); - - while (nShift < 29) - { - dDiff *= 256.0; - nShift++; - } - while (nShift > 29) - { - dDiff /= 256.0; - nShift--; - } - - return dDiff; -} - QDateTime ClientModel::getLastBlockDate() const { - return QDateTime::fromTime_t(pindexBest->GetBlockTime()); + if (pindexBest) + return QDateTime::fromTime_t(pindexBest->GetBlockTime()); + else if(!isTestNet()) + return QDateTime::fromTime_t(1231006505); // Genesis block's time + else + return QDateTime::fromTime_t(1296688602); // Genesis block's time (testnet) +} + +double ClientModel::getVerificationProgress() const +{ + return Checkpoints::GuessVerificationProgress(pindexBest); } void ClientModel::updateTimer() @@ -94,11 +72,18 @@ void ClientModel::updateTimer() int newNumBlocks = getNumBlocks(); int newNumBlocksOfPeers = getNumBlocksOfPeers(); - if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers) - emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers); + // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state + if (cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers || + cachedReindexing != fReindex || cachedImporting != fImporting) + { + cachedNumBlocks = newNumBlocks; + cachedNumBlocksOfPeers = newNumBlocksOfPeers; + cachedReindexing = fReindex; + cachedImporting = fImporting; - cachedNumBlocks = newNumBlocks; - cachedNumBlocksOfPeers = newNumBlocksOfPeers; + // ensure we return the maximum of newNumBlocksOfPeers and newNumBlocks to not create weird displays in the GUI + emit numBlocksChanged(newNumBlocks, std::max(newNumBlocksOfPeers, newNumBlocks)); + } } void ClientModel::updateNumConnections(int numConnections) @@ -116,13 +101,11 @@ void ClientModel::updateAlert(const QString &hash, int status) CAlert alert = CAlert::getAlertByHash(hash_256); if(!alert.IsNull()) { - emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false); + emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); } } - // Emit a numBlocksChanged when the status message changes, - // so that the view recomputes and updates the status bar. - emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers()); + emit alertsChanged(getStatusBarWarnings()); } bool ClientModel::isTestNet() const @@ -135,6 +118,18 @@ bool ClientModel::inInitialBlockDownload() const return IsInitialBlockDownload(); } +enum BlockSource ClientModel::getBlockSource() const +{ + if (fReindex) + return BLOCK_SOURCE_REINDEX; + else if (fImporting) + return BLOCK_SOURCE_DISK; + else if (getNumConnections() > 0) + return BLOCK_SOURCE_NETWORK; + + return BLOCK_SOURCE_NONE; +} + int ClientModel::getNumBlocksOfPeers() const { return GetNumBlocksOfPeers(); @@ -160,6 +155,11 @@ QString ClientModel::formatBuildDate() const return QString::fromStdString(CLIENT_DATE); } +bool ClientModel::isReleaseVersion() const +{ + return CLIENT_VERSION_IS_RELEASE; +} + QString ClientModel::clientName() const { return QString::fromStdString(CLIENT_NAME); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index fff9634..f9d491a 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -13,10 +13,18 @@ class QDateTime; class QTimer; QT_END_NAMESPACE +enum BlockSource { + BLOCK_SOURCE_NONE, + BLOCK_SOURCE_REINDEX, + BLOCK_SOURCE_DISK, + BLOCK_SOURCE_NETWORK +}; + /** Model for Bitcoin network client. */ class ClientModel : public QObject { Q_OBJECT + public: explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0); ~ClientModel(); @@ -27,15 +35,15 @@ public: int getNumBlocks() const; int getNumBlocksAtStartup(); - int getHashrate() const; - double GetDifficulty() const; - + double getVerificationProgress() const; QDateTime getLastBlockDate() const; //! Return true if client connected to testnet bool isTestNet() const; //! Return true if core is doing initial block download bool inInitialBlockDownload() const; + //! Return true if core is importing blocks + enum BlockSource getBlockSource() const; //! Return conservative estimate of total number of blocks, or 0 if unknown int getNumBlocksOfPeers() const; //! Return warnings to be displayed in status bar @@ -43,6 +51,7 @@ public: QString formatFullVersion() const; QString formatBuildDate() const; + bool isReleaseVersion() const; QString clientName() const; QString formatClientStartupTime() const; @@ -51,7 +60,8 @@ private: int cachedNumBlocks; int cachedNumBlocksOfPeers; - int cachedHashrate; + bool cachedReindexing; + bool cachedImporting; int numBlocksAtStartup; @@ -59,12 +69,14 @@ private: void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); + signals: void numConnectionsChanged(int count); void numBlocksChanged(int count, int countOfPeers); + void alertsChanged(const QString &warnings); - //! Asynchronous error notification - void error(const QString &title, const QString &message, bool modal); + //! Asynchronous message notification + void message(const QString &title, const QString &message, unsigned int style); public slots: void updateTimer(); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp new file mode 100644 index 0000000..fe8e963 --- /dev/null +++ b/src/qt/coincontroldialog.cpp @@ -0,0 +1,773 @@ +#include "coincontroldialog.h" +#include "ui_coincontroldialog.h" + +#include "init.h" +#include "bitcoinunits.h" +#include "walletmodel.h" +#include "addresstablemodel.h" +#include "optionsmodel.h" +#include "guiutil.h" +#include "coincontrol.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +QList CoinControlDialog::payAmounts; +CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); + +CoinControlDialog::CoinControlDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CoinControlDialog), + model(0) +{ + ui->setupUi(this); + + // context menu actions + QAction *copyAddressAction = new QAction(tr("Copy address"), this); + QAction *copyLabelAction = new QAction(tr("Copy label"), this); + QAction *copyAmountAction = new QAction(tr("Copy amount"), this); + copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this + lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this + unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this + + // context menu + contextMenu = new QMenu(); + contextMenu->addAction(copyAddressAction); + contextMenu->addAction(copyLabelAction); + contextMenu->addAction(copyAmountAction); + contextMenu->addAction(copyTransactionHashAction); + contextMenu->addSeparator(); + contextMenu->addAction(lockAction); + contextMenu->addAction(unlockAction); + + // context menu signals + connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); + connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); + connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); + connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash())); + connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin())); + connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin())); + + // clipboard actions + QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); + QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this); + 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 low output"), this); + QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); + + connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity())); + connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount())); + 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())); + + ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); + ui->labelCoinControlAmount->addAction(clipboardAmountAction); + ui->labelCoinControlFee->addAction(clipboardFeeAction); + ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); + ui->labelCoinControlBytes->addAction(clipboardBytesAction); + ui->labelCoinControlPriority->addAction(clipboardPriorityAction); + ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); + ui->labelCoinControlChange->addAction(clipboardChangeAction); + + // toggle tree/list mode + connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool))); + connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool))); + + // click on checkbox + connect(ui->treeWidget, SIGNAL(itemChanged( QTreeWidgetItem*, int)), this, SLOT(viewItemChanged( QTreeWidgetItem*, int))); + + // click on header + #if QT_VERSION < 0x050000 + ui->treeWidget->header()->setClickable(true); + #else + ui->treeWidget->header()->setSectionsClickable(true); + #endif + connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int))); + + // ok button + connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*))); + + // (un)select all + connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); + + 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->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but dont show it + + // default view is sorted by amount desc + sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder); +} + +CoinControlDialog::~CoinControlDialog() +{ + delete ui; +} + +void CoinControlDialog::setModel(WalletModel *model) +{ + this->model = model; + + if(model && model->getOptionsModel() && model->getAddressTableModel()) + { + updateView(); + updateLabelLocked(); + 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) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) + done(QDialog::Accepted); // closes the dialog +} + +// (un)select all +void CoinControlDialog::buttonSelectAllClicked() +{ + Qt::CheckState state = Qt::Checked; + for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) + { + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked) + { + state = Qt::Unchecked; + break; + } + } + ui->treeWidget->setEnabled(false); + for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state) + ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state); + ui->treeWidget->setEnabled(true); + if (state == Qt::Unchecked) + coinControl->UnSelectAll(); // just to be sure + CoinControlDialog::updateLabels(model, this); +} + +// context menu +void CoinControlDialog::showMenu(const QPoint &point) +{ + QTreeWidgetItem *item = ui->treeWidget->itemAt(point); + if(item) + { + contextMenuItem = item; + + // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu + if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) + { + copyTransactionHashAction->setEnabled(true); + if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) + { + lockAction->setEnabled(false); + unlockAction->setEnabled(true); + } + else + { + lockAction->setEnabled(true); + unlockAction->setEnabled(false); + } + } + else // this means click on parent node in tree mode -> disable all + { + copyTransactionHashAction->setEnabled(false); + lockAction->setEnabled(false); + unlockAction->setEnabled(false); + } + + // show context menu + contextMenu->exec(QCursor::pos()); + } +} + +// context menu action: copy amount +void CoinControlDialog::copyAmount() +{ + GUIUtil::setClipboard(contextMenuItem->text(COLUMN_AMOUNT)); +} + +// context menu action: copy label +void CoinControlDialog::copyLabel() +{ + if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_LABEL).length() == 0 && contextMenuItem->parent()) + GUIUtil::setClipboard(contextMenuItem->parent()->text(COLUMN_LABEL)); + else + GUIUtil::setClipboard(contextMenuItem->text(COLUMN_LABEL)); +} + +// context menu action: copy address +void CoinControlDialog::copyAddress() +{ + if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && contextMenuItem->parent()) + GUIUtil::setClipboard(contextMenuItem->parent()->text(COLUMN_ADDRESS)); + else + GUIUtil::setClipboard(contextMenuItem->text(COLUMN_ADDRESS)); +} + +// context menu action: copy transaction id +void CoinControlDialog::copyTransactionHash() +{ + GUIUtil::setClipboard(contextMenuItem->text(COLUMN_TXHASH)); +} + +// context menu action: lock coin +void CoinControlDialog::lockCoin() +{ + if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) + contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); + + COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + model->lockCoin(outpt); + contextMenuItem->setDisabled(true); + contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed")); + updateLabelLocked(); +} + +// context menu action: unlock coin +void CoinControlDialog::unlockCoin() +{ + COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + model->unlockCoin(outpt); + contextMenuItem->setDisabled(false); + contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon()); + updateLabelLocked(); +} + +// copy label "Quantity" to clipboard +void CoinControlDialog::clipboardQuantity() +{ + GUIUtil::setClipboard(ui->labelCoinControlQuantity->text()); +} + +// copy label "Amount" to clipboard +void CoinControlDialog::clipboardAmount() +{ + GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" "))); +} + +// copy label "Fee" to clipboard +void CoinControlDialog::clipboardFee() +{ + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" "))); +} + +// copy label "After fee" to clipboard +void CoinControlDialog::clipboardAfterFee() +{ + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" "))); +} + +// copy label "Bytes" to clipboard +void CoinControlDialog::clipboardBytes() +{ + GUIUtil::setClipboard(ui->labelCoinControlBytes->text()); +} + +// copy label "Priority" to clipboard +void CoinControlDialog::clipboardPriority() +{ + GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); +} + +// copy label "Low output" to clipboard +void CoinControlDialog::clipboardLowOutput() +{ + GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text()); +} + +// copy label "Change" to clipboard +void CoinControlDialog::clipboardChange() +{ + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" "))); +} + +// treeview: sort +void CoinControlDialog::sortView(int column, Qt::SortOrder order) +{ + sortColumn = column; + sortOrder = order; + ui->treeWidget->sortItems(column, order); + ui->treeWidget->header()->setSortIndicator((sortColumn == COLUMN_AMOUNT_INT64 ? COLUMN_AMOUNT : (sortColumn == COLUMN_PRIORITY_INT64 ? COLUMN_PRIORITY : sortColumn)), sortOrder); +} + +// treeview: clicked on header +void CoinControlDialog::headerSectionClicked(int logicalIndex) +{ + if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing + { + ui->treeWidget->header()->setSortIndicator((sortColumn == COLUMN_AMOUNT_INT64 ? COLUMN_AMOUNT : (sortColumn == COLUMN_PRIORITY_INT64 ? COLUMN_PRIORITY : sortColumn)), sortOrder); + } + else + { + if (logicalIndex == COLUMN_AMOUNT) // sort by amount + logicalIndex = COLUMN_AMOUNT_INT64; + + if (logicalIndex == COLUMN_PRIORITY) // sort by priority + logicalIndex = COLUMN_PRIORITY_INT64; + + if (sortColumn == logicalIndex) + sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder); + else + { + sortColumn = logicalIndex; + sortOrder = ((sortColumn == COLUMN_AMOUNT_INT64 || sortColumn == COLUMN_PRIORITY_INT64 || sortColumn == COLUMN_DATE || sortColumn == COLUMN_CONFIRMATIONS) ? Qt::DescendingOrder : Qt::AscendingOrder); // if amount,date,conf,priority then default => desc, else default => asc + } + + sortView(sortColumn, sortOrder); + } +} + +// toggle tree mode +void CoinControlDialog::radioTreeMode(bool checked) +{ + if (checked && model) + updateView(); +} + +// toggle list mode +void CoinControlDialog::radioListMode(bool checked) +{ + if (checked && model) + updateView(); +} + +// checkbox clicked by user +void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) +{ + if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) + { + COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()); + + if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) + coinControl->UnSelect(outpt); + else if (item->isDisabled()) // locked (this happens if "check all" through parent node) + item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); + else + coinControl->Select(outpt); + + // selection changed -> update labels + if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all + CoinControlDialog::updateLabels(model, this); + } +} + +// helper function, return human readable label for priority number +QString CoinControlDialog::getPriorityLabel(double dPriority) +{ + if (CTransaction::AllowFree(dPriority)) // at least medium + { + if (CTransaction::AllowFree(dPriority / 10000)) return tr("highest"); + else if (CTransaction::AllowFree(dPriority / 1000)) return tr("high"); + else if (CTransaction::AllowFree(dPriority / 100)) return tr("medium-high"); + else return tr("medium"); + } + else + { + if (CTransaction::AllowFree(dPriority * 100)) return tr("low-medium"); + else if (CTransaction::AllowFree(dPriority * 10000)) return tr("low"); + else return tr("lowest"); + } +} + +// shows count of locked unspent outputs +void CoinControlDialog::updateLabelLocked() +{ + vector vOutpts; + model->listLockedCoins(vOutpts); + if (vOutpts.size() > 0) + { + ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size())); + ui->labelLocked->setVisible(true); + } + else ui->labelLocked->setVisible(false); +} + +void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) +{ + if (!model) return; + + // nPayAmount + qint64 nPayAmount = 0; + bool fLowOutput = false; + bool fDust = false; + unsigned int nQuantityDust = 0; + CTransaction txDummy; + foreach(const qint64 &amount, CoinControlDialog::payAmounts) + { + nPayAmount += amount; + + if (amount > 0) + { + if (amount < CENT) { + fLowOutput = true; + nQuantityDust++; + } + + CTxOut txout(amount, (CScript)vector(24, 0)); + txDummy.vout.push_back(txout); + if (txout.IsDust()) + fDust = true; + } + } + + QString sPriorityLabel = ""; + int64 nAmount = 0; + int64 nPayFee = 0; + int64 nAfterFee = 0; + int64 nChange = 0; + unsigned int nBytes = 0; + unsigned int nBytesInputs = 0; + double dPriority = 0; + double dPriorityInputs = 0; + unsigned int nQuantity = 0; + + vector vCoinControl; + vector vOutputs; + coinControl->ListSelected(vCoinControl); + model->getOutputs(vCoinControl, vOutputs); + + BOOST_FOREACH(const COutput& out, vOutputs) + { + // unselect already spent, very unlikely scenario, this could happen when selected are spent elsewhere, like rpc or another computer + if (out.tx->IsSpent(out.i)) + { + uint256 txhash = out.tx->GetHash(); + COutPoint outpt(txhash, out.i); + coinControl->UnSelect(outpt); + continue; + } + + // Quantity + nQuantity++; + + // Amount + nAmount += out.tx->vout[out.i].nValue; + + // Priority + dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); + + // Bytes + CTxDestination address; + if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + { + CPubKey pubkey; + CKeyID *keyid = boost::get(&address); + if (keyid && model->getPubKey(*keyid, pubkey)) + nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); + else + nBytesInputs += 148; // in all error cases, simply assume 148 here + } + else nBytesInputs += 148; + } + + // calculation + if (nQuantity > 0) + { + // Bytes + nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here + + // Priority + dPriority = dPriorityInputs / nBytes; + sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority); + + // Fee + int64 nFee = nTransactionFee * (1 + (int64)nBytes / 1000); + + // Min Fee + int64 nMinFee = CTransaction::nMinTxFee * (1 + (int64)nBytes / 1000) + CTransaction::nMinTxFee * nQuantityDust; + if (CTransaction::AllowFree(dPriority) && nBytes < 5000) + nMinFee = 0; + + nPayFee = max(nFee, nMinFee); + + if (nPayAmount > 0) + { + nChange = nAmount - nPayFee - nPayAmount; + + // require CTransaction::nMinTxFee if any output is less than 0.01 + if (nPayFee < CTransaction::nMinTxFee && fLowOutput) + { + nChange = nChange + nPayFee - CTransaction::nMinTxFee; + nPayFee = CTransaction::nMinTxFee * nQuantityDust; + } + + // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee + if (nPayFee < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) + { + if (nChange < CTransaction::nMinTxFee) // change < 0.0001 => simply move all change to fees + { + nPayFee += nChange; + nChange = 0; + } + else + { + nChange = nChange + nPayFee - CTransaction::nMinTxFee; + nPayFee = CTransaction::nMinTxFee; + } + } + + // Never create dust outputs; if we would, just add the dust to the fee. + if (nChange > 0 && nChange < CENT) + { + CTxOut txout(nChange, (CScript)vector(24, 0)); + if (txout.IsDust()) + { + nPayFee += nChange; + nChange = 0; + } + } + + if (nChange == 0) + nBytes -= 34; + } + + // after fee + nAfterFee = nAmount - nPayFee; + if (nAfterFee < 0) + nAfterFee = 0; + } + + // actually update labels + int nDisplayUnit = BitcoinUnits::BTC; + if (model && model->getOptionsModel()) + nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); + + QLabel *l1 = dialog->findChild("labelCoinControlQuantity"); + QLabel *l2 = dialog->findChild("labelCoinControlAmount"); + QLabel *l3 = dialog->findChild("labelCoinControlFee"); + QLabel *l4 = dialog->findChild("labelCoinControlAfterFee"); + QLabel *l5 = dialog->findChild("labelCoinControlBytes"); + QLabel *l6 = dialog->findChild("labelCoinControlPriority"); + QLabel *l7 = dialog->findChild("labelCoinControlLowOutput"); + QLabel *l8 = dialog->findChild("labelCoinControlChange"); + + // enable/disable "low output" and "change" + dialog->findChild("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0); + dialog->findChild("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0); + dialog->findChild("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0); + dialog->findChild("labelCoinControlChange") ->setEnabled(nPayAmount > 0); + + // stats + l1->setText(QString::number(nQuantity)); // Quantity + l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount + l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee + l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee + l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes + l6->setText(sPriorityLabel); // Priority + l7->setText((fLowOutput ? (fDust ? tr("DUST") : tr("yes")) : tr("no"))); // Low Output / Dust + l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change + + // turn labels "red" + l5->setStyleSheet((nBytes >= 5000) ? "color:red;" : ""); // Bytes >= 5000 + l6->setStyleSheet((!CTransaction::AllowFree(dPriority)) ? "color:red;" : ""); // Priority < "medium" + l7->setStyleSheet((fLowOutput) ? "color:red;" : ""); // Low Output = "yes" + l8->setStyleSheet((nChange > 0 && nChange < CENT) ? "color:red;" : ""); // Change < 0.01BTC + + // tool tips + l5->setToolTip(tr("This label turns red, if the transaction size is bigger than 5000 bytes.\n\n This means a fee of at least %1 per kb is required.\n\n Can vary +/- 1 Byte per input.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee))); + l6->setToolTip(tr("Transactions with higher priority get more likely into a block.\n\nThis label turns red, if the priority is smaller than \"medium\".\n\n This means a fee of at least %1 per kb is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee))); + l7->setToolTip(tr("This label turns red, if any recipient receives an amount smaller than %1.\n\n This means a fee of at least %2 is required. \n\n Amounts below 0.546 times the minimum relay fee are shown as DUST.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee))); + l8->setToolTip(tr("This label turns red, if the change is smaller than %1.\n\n This means a fee of at least %2 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee))); + dialog->findChild("labelCoinControlBytesText") ->setToolTip(l5->toolTip()); + dialog->findChild("labelCoinControlPriorityText") ->setToolTip(l6->toolTip()); + dialog->findChild("labelCoinControlLowOutputText")->setToolTip(l7->toolTip()); + dialog->findChild("labelCoinControlChangeText") ->setToolTip(l8->toolTip()); + + // Insufficient funds + QLabel *label = dialog->findChild("labelCoinControlInsuffFunds"); + if (label) + label->setVisible(nChange < 0); +} + +void CoinControlDialog::updateView() +{ + bool treeMode = ui->radioTreeMode->isChecked(); + + ui->treeWidget->clear(); + ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox + ui->treeWidget->setAlternatingRowColors(!treeMode); + QFlags flgCheckbox=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; + QFlags flgTristate=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + + int nDisplayUnit = BitcoinUnits::BTC; + if (model && model->getOptionsModel()) + nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); + + map > mapCoins; + model->listCoins(mapCoins); + + BOOST_FOREACH(PAIRTYPE(QString, vector) coins, mapCoins) + { + QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem(); + QString sWalletAddress = coins.first; + QString sWalletLabel = ""; + if (model->getAddressTableModel()) + sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); + if (sWalletLabel.length() == 0) + sWalletLabel = tr("(no label)"); + + if (treeMode) + { + // wallet address + ui->treeWidget->addTopLevelItem(itemWalletAddress); + + itemWalletAddress->setFlags(flgTristate); + itemWalletAddress->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); + + for (int i = 0; i < ui->treeWidget->columnCount(); i++) + itemWalletAddress->setBackground(i, QColor(248, 247, 246)); + + // label + itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel); + + // address + itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress); + } + + int64 nSum = 0; + double dPrioritySum = 0; + int nChildren = 0; + int nInputSum = 0; + BOOST_FOREACH(const COutput& out, coins.second) + { + int nInputSize = 148; // 180 if uncompressed public key + nSum += out.tx->vout[out.i].nValue; + nChildren++; + + QTreeWidgetItem *itemOutput; + if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress); + else itemOutput = new QTreeWidgetItem(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)) + { + sAddress = CBitcoinAddress(outputAddress).ToString().c_str(); + + // 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(&outputAddress); + if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed()) + nInputSize = 180; + } + + // label + if (!(sAddress == sWalletAddress)) // change + { + // tooltip from where the change comes from + itemOutput->setToolTip(COLUMN_LABEL, tr("change from %1 (%2)").arg(sWalletLabel).arg(sWalletAddress)); + itemOutput->setText(COLUMN_LABEL, tr("(change)")); + } + else if (!treeMode) + { + QString sLabel = ""; + if (model->getAddressTableModel()) + sLabel = model->getAddressTableModel()->labelForAddress(sAddress); + if (sLabel.length() == 0) + sLabel = tr("(no label)"); + itemOutput->setText(COLUMN_LABEL, sLabel); + } + + // 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 + + // date + itemOutput->setText(COLUMN_DATE, QDateTime::fromTime_t(out.tx->GetTxTime()).toString("yy-MM-dd hh:mm")); + + // 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)); + itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64)dPriority), 20, " ")); + dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); + nInputSum += nInputSize; + + // transaction hash + uint256 txhash = out.tx->GetHash(); + itemOutput->setText(COLUMN_TXHASH, txhash.GetHex().c_str()); + + // vout index + itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i)); + + // disable locked coins + if (model->isLockedCoin(txhash, out.i)) + { + COutPoint outpt(txhash, out.i); + coinControl->UnSelect(outpt); // just to be sure + itemOutput->setDisabled(true); + itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed")); + } + + // set checkbox + if (coinControl->IsSelected(txhash, out.i)) + itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Checked); + } + + // 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)); + itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64)dPrioritySum), 20, " ")); + } + } + + // expand all partially selected + if (treeMode) + { + for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked) + ui->treeWidget->topLevelItem(i)->setExpanded(true); + } + + // sort view + sortView(sortColumn, sortOrder); + ui->treeWidget->setEnabled(true); +} diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h new file mode 100644 index 0000000..9903bd4 --- /dev/null +++ b/src/qt/coincontroldialog.h @@ -0,0 +1,92 @@ +#ifndef COINCONTROLDIALOG_H +#define COINCONTROLDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { + class CoinControlDialog; +} +class WalletModel; +class CCoinControl; + +class CoinControlDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CoinControlDialog(QWidget *parent = 0); + ~CoinControlDialog(); + + void setModel(WalletModel *model); + + // static because also called from sendcoinsdialog + static void updateLabels(WalletModel*, QDialog*); + static QString getPriorityLabel(double); + + static QList payAmounts; + static CCoinControl *coinControl; + +private: + Ui::CoinControlDialog *ui; + WalletModel *model; + int sortColumn; + Qt::SortOrder sortOrder; + + QMenu *contextMenu; + QTreeWidgetItem *contextMenuItem; + QAction *copyTransactionHashAction; + QAction *lockAction; + QAction *unlockAction; + + QString strPad(QString, int, QString); + void sortView(int, Qt::SortOrder); + void updateView(); + + enum + { + COLUMN_CHECKBOX, + COLUMN_AMOUNT, + COLUMN_LABEL, + COLUMN_ADDRESS, + COLUMN_DATE, + COLUMN_CONFIRMATIONS, + COLUMN_PRIORITY, + COLUMN_TXHASH, + COLUMN_VOUT_INDEX, + COLUMN_AMOUNT_INT64, + COLUMN_PRIORITY_INT64 + }; + +private slots: + void showMenu(const QPoint &); + void copyAmount(); + void copyLabel(); + void copyAddress(); + void copyTransactionHash(); + void lockCoin(); + void unlockCoin(); + void clipboardQuantity(); + void clipboardAmount(); + void clipboardFee(); + void clipboardAfterFee(); + void clipboardBytes(); + void clipboardPriority(); + void clipboardLowOutput(); + void clipboardChange(); + void radioTreeMode(bool); + void radioListMode(bool); + void viewItemChanged(QTreeWidgetItem*, int); + void headerSectionClicked(int); + void buttonBoxClicked(QAbstractButton*); + void buttonSelectAllClicked(); + void updateLabelLocked(); +}; + +#endif // COINCONTROLDIALOG_H diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp new file mode 100644 index 0000000..aa75a49 --- /dev/null +++ b/src/qt/coincontroltreewidget.cpp @@ -0,0 +1,28 @@ +#include "coincontroltreewidget.h" +#include "coincontroldialog.h" + +CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) : + QTreeWidget(parent) +{ + +} + +void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Space) // press spacebar -> select checkbox + { + event->ignore(); + int COLUMN_CHECKBOX = 0; + this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked)); + } + else if (event->key() == Qt::Key_Escape) // press esc -> close dialog + { + event->ignore(); + CoinControlDialog *coinControlDialog = (CoinControlDialog*)this->parentWidget(); + coinControlDialog->done(QDialog::Accepted); + } + else + { + this->QTreeWidget::keyPressEvent(event); + } +} \ No newline at end of file diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h new file mode 100644 index 0000000..d981f72 --- /dev/null +++ b/src/qt/coincontroltreewidget.h @@ -0,0 +1,17 @@ +#ifndef COINCONTROLTREEWIDGET_H +#define COINCONTROLTREEWIDGET_H + +#include +#include + +class CoinControlTreeWidget : public QTreeWidget { +Q_OBJECT + +public: + explicit CoinControlTreeWidget(QWidget *parent = 0); + +protected: + virtual void keyPressEvent(QKeyEvent *event); +}; + +#endif // COINCONTROLTREEWIDGET_H \ No newline at end of file diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h index 6c9dcba..c4504ee 100644 --- a/src/qt/csvmodelwriter.h +++ b/src/qt/csvmodelwriter.h @@ -14,6 +14,7 @@ QT_END_NAMESPACE class CSVModelWriter : public QObject { Q_OBJECT + public: explicit CSVModelWriter(const QString &filename, QObject *parent = 0); @@ -36,11 +37,6 @@ private: int role; }; QList columns; - -signals: - -public slots: - }; #endif // CSVMODELWRITER_H diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 62cda51..35946bd 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -1,5 +1,6 @@ #include "editaddressdialog.h" #include "ui_editaddressdialog.h" + #include "addresstablemodel.h" #include "guiutil.h" @@ -25,7 +26,7 @@ EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : break; case EditReceivingAddress: setWindowTitle(tr("Edit receiving address")); - ui->addressEdit->setDisabled(true); + ui->addressEdit->setEnabled(false); break; case EditSendingAddress: setWindowTitle(tr("Edit sending address")); @@ -44,6 +45,9 @@ EditAddressDialog::~EditAddressDialog() void EditAddressDialog::setModel(AddressTableModel *model) { this->model = model; + if(!model) + return; + mapper->setModel(model); mapper->addMapping(ui->labelEdit, AddressTableModel::Label); mapper->addMapping(ui->addressEdit, AddressTableModel::Address); @@ -58,6 +62,7 @@ bool EditAddressDialog::saveCurrentRow() { if(!model) return false; + switch(mode) { case NewReceivingAddress: @@ -82,35 +87,39 @@ void EditAddressDialog::accept() { if(!model) return; + if(!saveCurrentRow()) { switch(model->getEditStatus()) { - case AddressTableModel::DUPLICATE_ADDRESS: - QMessageBox::warning(this, windowTitle(), - tr("The entered address \"%1\" is already in the address book.").arg(ui->addressEdit->text()), - QMessageBox::Ok, QMessageBox::Ok); + case AddressTableModel::OK: + // Failed with unknown reason. Just reject. + break; + case AddressTableModel::NO_CHANGES: + // No changes were made during edit operation. Just reject. break; case AddressTableModel::INVALID_ADDRESS: QMessageBox::warning(this, windowTitle(), tr("The entered address \"%1\" is not a valid CasinoCoin address.").arg(ui->addressEdit->text()), QMessageBox::Ok, QMessageBox::Ok); - return; + break; + case AddressTableModel::DUPLICATE_ADDRESS: + QMessageBox::warning(this, windowTitle(), + tr("The entered address \"%1\" is already in the address book.").arg(ui->addressEdit->text()), + QMessageBox::Ok, QMessageBox::Ok); + break; case AddressTableModel::WALLET_UNLOCK_FAILURE: QMessageBox::critical(this, windowTitle(), tr("Could not unlock wallet."), QMessageBox::Ok, QMessageBox::Ok); - return; + break; case AddressTableModel::KEY_GENERATION_FAILURE: QMessageBox::critical(this, windowTitle(), tr("New key generation failed."), QMessageBox::Ok, QMessageBox::Ok); - return; - case AddressTableModel::OK: - // Failed with unknown reason. Just reject. break; - } + } return; } QDialog::accept(); diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index 7ec053f..44e5023 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -3,15 +3,15 @@ #include -QT_BEGIN_NAMESPACE -class QDataWidgetMapper; -QT_END_NAMESPACE - namespace Ui { class EditAddressDialog; } class AddressTableModel; +QT_BEGIN_NAMESPACE +class QDataWidgetMapper; +QT_END_NAMESPACE + /** Dialog for editing an address and associated information. */ class EditAddressDialog : public QDialog @@ -27,15 +27,17 @@ public: }; explicit EditAddressDialog(Mode mode, QWidget *parent = 0); - ~EditAddressDialog(); + ~EditAddressDialog(); void setModel(AddressTableModel *model); void loadRow(int row); - void accept(); - QString getAddress() const; void setAddress(const QString &address); + +public slots: + void accept(); + private: bool saveCurrentRow(); diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui index f920167..105c2f6 100644 --- a/src/qt/forms/aboutdialog.ui +++ b/src/qt/forms/aboutdialog.ui @@ -63,10 +63,7 @@ IBeamCursor - 0.3.666-beta - - - Qt::RichText + 1.1.0.0 Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse @@ -88,6 +85,23 @@ + + + + IBeamCursor + + + Copyright &copy; 2009-2014 The Bitcoin developers +Copyright &copy; 2013-2014 The CasinoCoin developers + + + Qt::RichText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + @@ -95,18 +109,14 @@ - Copyright © 2009-2012 Bitcoin Developers - Copyright © 2011-2012 Litecoin Developers - Copyright © 2013 CasinoCoin Developers +This is experimental software. - This is experimental software. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. - Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - - Official forum: http://forum.casinoco.in - +Official forum: http://forum.casinoco.in +
true diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index b4368e7..49dbdac 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -16,9 +16,6 @@ - - These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Qt::PlainText @@ -58,7 +55,7 @@ - + Create a new address @@ -72,7 +69,7 @@ - + Copy the currently selected address to the system clipboard @@ -99,10 +96,10 @@ - Sign a message to prove you own a Bitcoin address + Sign a message to prove you own a CasinoCoin address - &Sign Message + Sign &Message @@ -113,7 +110,7 @@ - Verify a message to ensure it was signed with a specified Bitcoin address + Verify a message to ensure it was signed with a specified CasinoCoin address &Verify Message @@ -125,9 +122,9 @@ - + - Delete the currently selected address from the list. Only sending addresses can be deleted. + Delete the currently selected address from the list &Delete @@ -151,6 +148,20 @@ + + + + Export the data in the current tab to a file + + + &Export + + + + :/icons/export:/icons/export + + + diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui new file mode 100644 index 0000000..58f6557 --- /dev/null +++ b/src/qt/forms/coincontroldialog.ui @@ -0,0 +1,556 @@ + + + CoinControlDialog + + + + 0 + 0 + 1000 + 500 + + + + Coin Control + + + + + + 0 + + + 10 + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + Quantity: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Bytes: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + Amount: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Priority: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + Fee: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + font-weight:bold; + + + Low Output: + + + + + + + false + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + After Fee: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + font-weight:bold; + + + Change: + + + + + + + false + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + + 0 + 40 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + 10 + 0 + 781 + 41 + + + + + 14 + + + + + + 0 + 0 + + + + (un)select all + + + + + + + + 0 + 0 + + + + Tree mode + + + true + + + + + + + + 0 + 0 + + + + List mode + + + + + + + (1 locked) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::CustomContextMenu + + + false + + + 11 + + + true + + + false + + + + + + + + + Amount + + + + + Label + + + + + Address + + + + + Date + + + + + Confirmations + + + Confirmed + + + + + Priority + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + CoinControlTreeWidget + QTreeWidget +
coincontroltreewidget.h
+
+
+ + +
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 62605b4..1f91d21 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -23,7 +23,7 @@ QTabWidget::North
- 1 + 0 @@ -33,7 +33,7 @@ - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Qt::PlainText @@ -44,7 +44,7 @@ - + @@ -62,7 +62,7 @@ - + Qt::Horizontal @@ -86,16 +86,6 @@
- - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - &Detach databases at shutdown - - - @@ -109,6 +99,36 @@ + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Reset all client options to default. + + + &Reset Options + + + false + + + + +
@@ -343,6 +363,16 @@
+ + + + Whether to show coin control features or not. + + + Display coin &control features (experts only!) + + + @@ -432,12 +462,6 @@ false - - false - - - false - diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index a229e04..e1dc0b1 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -13,308 +13,308 @@ Form - + - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - 11 - 75 - true - - - - Wallet - - - - - - - The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - - - QLabel { color: red; } - - - (out of sync) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 12 - - - 12 - - - - - Balance: - - - - - - - - 75 - true - - - - IBeamCursor - - - Your current balance - - - 0 CSC - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - Unconfirmed: - - - - - - - - 75 - true - - - - IBeamCursor - - - Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - - - 0 CSC - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - Number of transactions: - - - - - - - Total number of transactions in wallet - - - 0 - - - - - - - Immature: - - - - - - - - 75 - true - - - - Mined balance that has not yet matured - - - 0 CSC - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - :/images/backg - - - false - - - Qt::AlignCenter - - - -2 - - - - + + + false + + + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; + + + true + + + 3 + + - + - - - QFrame::StyledPanel - - - QFrame::Raised - - - - + + + + + QFrame::NoFrame + + + QFrame::Plain + + - - - <b>Recent transactions</b> - - + + + + + + 75 + true + + + + Wallet + + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + QFormLayout::AllNonFixedFieldsGrow - - QLabel { color: red; } + + 12 - - (out of sync) + + 12 - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + Balance: + + + + + + + + 75 + true + + + + IBeamCursor + + + Your current balance + + + 0 CSC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Unconfirmed: + + + + + + + + 75 + true + + + + IBeamCursor + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + 0 CSC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Immature: + + + + + + + + 75 + true + + + + Mined balance that has not yet matured + + + 0 CSC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + - - - - - QListView { background: transparent; } - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QAbstractItemView::NoSelection - - - - - + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + :/images/backg + + + false + + + Qt::AlignCenter + + + -2 + + + + - - - Qt::Vertical - - - - 20 - 40 - - - + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + + <b>Recent transactions</b> + + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QListView { background: transparent; } + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoSelection + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + - - - + diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index 3462425..07aa5ee 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -36,7 +36,7 @@ - Bitcoin Core + CasinoCoin Core @@ -292,14 +292,14 @@ - Debug logfile + Debug log file - Open the CasinoCoin debug logfile from the current data directory. This can take a few seconds for large logfiles. + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. &Open @@ -333,9 +333,6 @@ false - - false - diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 5c333d8..dfb135a 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -6,14 +6,615 @@ 0 0 - 686 - 217 + 850 + 400 Send Coins - + + + 8 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + -1 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + 0 + + + 10 + + + 10 + + + + + 15 + + + + + + 0 + 0 + + + + + 75 + true + + + + font-weight:bold; + + + Coin Control Features + + + + + + + + + 8 + + + 10 + + + + + + + + Inputs... + + + + + + + automatically selected + + + 5 + + + + + + + + 75 + true + + + + color:red;font-weight:bold; + + + Insufficient funds! + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 1 + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + 0 + + + + + 20 + + + 0 + + + 10 + + + + + 10 + + + 14 + + + 10 + + + 4 + + + 6 + + + + + font-weight:bold; + + + Quantity: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Bytes: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + font-weight:bold; + + + Amount: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Priority: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + medium + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + font-weight:bold; + + + Fee: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Low Output: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + font-weight:bold; + + + After Fee: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Change: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BTC + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + 5 + + + 5 + + + + + custom change address + + + + + + + false + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + 3 + + + + + + + + + Qt::Vertical + + + + 800 + 1 + + + + + + + + + @@ -24,7 +625,7 @@ 0 0 - 666 + 830 165 @@ -64,7 +665,7 @@ Send to multiple recipients at once - &Add Recipient + Add &Recipient @@ -153,7 +754,7 @@ Confirm the send action - &Send + S&end diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index 22a3f8f..28553c5 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -52,23 +52,6 @@ - - - - 0 - - - - - true - - - Enter a label for this address to add it to your address book - - - - - @@ -90,7 +73,7 @@ - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) 34 @@ -147,6 +130,13 @@ + + + + Enter a label for this address to add it to your address book + + + diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 8128bdf..a72fe15 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -48,7 +48,7 @@ - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) 34 @@ -104,6 +104,16 @@ + + + + Signature + + + Qt::PlainText + + + @@ -145,10 +155,10 @@ - Sign the message to prove you own this Bitcoin address + Sign the message to prove you own this CasinoCoin address - &Sign Message + Sign &Message @@ -251,7 +261,7 @@ - The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) 34 @@ -291,10 +301,10 @@ - Verify the message to ensure it was signed with the specified Bitcoin address + Verify the message to ensure it was signed with the specified CasinoCoin address - &Verify Message + Verify &Message diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 405ba39..9241783 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -2,7 +2,7 @@ #define GUICONSTANTS_H /* Milliseconds between model updates */ -static const int MODEL_UPDATE_DELAY = 500; +static const int MODEL_UPDATE_DELAY = 250; /* AskPassphraseDialog -- Maximum passphrase length */ static const int MAX_PASSPHRASE_SIZE = 1024; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 660234c..48dcf98 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,20 +1,25 @@ +#include + #include "guiutil.h" + #include "bitcoinaddressvalidator.h" #include "walletmodel.h" #include "bitcoinunits.h" + #include "util.h" #include "init.h" -#include "base58.h" -#include #include #include #include #include +#if QT_VERSION >= 0x050000 +#include +#else #include -#include // For Qt::escape +#endif +#include // for Qt::mightBeRichText #include -#include #include #include #include @@ -78,18 +83,20 @@ void setupAmountWidget(QLineEdit *widget, QWidget *parent) bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) { - if(uri.scheme() != QString("casinocoin")) - return false; - - // check if the address is valid - CBitcoinAddress addressFromUri(uri.path().toStdString()); - if (!addressFromUri.IsValid()) + // return if URI is not valid or is no bitcoin URI + if(!uri.isValid() || uri.scheme() != QString("casinocoin")) return false; SendCoinsRecipient rv; rv.address = uri.path(); rv.amount = 0; + +#if QT_VERSION < 0x050000 QList > items = uri.queryItems(); +#else + QUrlQuery uriQuery(uri); + QList > items = uriQuery.queryItems(); +#endif for (QList >::iterator i = items.begin(); i != items.end(); i++) { bool fShouldReturnFalse = false; @@ -128,10 +135,10 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) bool parseBitcoinURI(QString uri, SendCoinsRecipient *out) { - // Convert casinocoin:// to casinocoin: + // Convert bitcoin:// to bitcoin: // - // Cannot handle this later, because casinocoin:// will cause Qt to see the part after // as host, - // which will lowercase it (and thus invalidate the address). + // Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host, + // which will lower-case it (and thus invalidate the address). if(uri.startsWith("casinocoin://")) { uri.replace(0, 11, "casinocoin:"); @@ -142,7 +149,11 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out) QString HtmlEscape(const QString& str, bool fMultiLine) { +#if QT_VERSION < 0x050000 QString escaped = Qt::escape(str); +#else + QString escaped = str.toHtmlEscaped(); +#endif if(fMultiLine) { escaped = escaped.replace("\n", "
\n"); @@ -163,11 +174,19 @@ void copyEntryData(QAbstractItemView *view, int column, int role) if(!selection.isEmpty()) { - // Copy first item - QApplication::clipboard()->setText(selection.at(0).data(role).toString()); + // Copy first item (global clipboard) + QApplication::clipboard()->setText(selection.at(0).data(role).toString(), QClipboard::Clipboard); + // Copy first item (global mouse selection for e.g. X11 - NOP on Windows) + QApplication::clipboard()->setText(selection.at(0).data(role).toString(), QClipboard::Selection); } } +void setClipboard(const QString& str) +{ + QApplication::clipboard()->setText(str, QClipboard::Clipboard); + QApplication::clipboard()->setText(str, QClipboard::Selection); +} + QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, @@ -177,7 +196,11 @@ QString getSaveFileName(QWidget *parent, const QString &caption, QString myDir; if(dir.isEmpty()) // Default to user documents location { +#if QT_VERSION < 0x050000 myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); +#else + myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); +#endif } else { @@ -216,7 +239,7 @@ QString getSaveFileName(QWidget *parent, const QString &caption, Qt::ConnectionType blockingGUIThreadConnection() { - if(QThread::currentThread() != QCoreApplication::instance()->thread()) + if(QThread::currentThread() != qApp->thread()) { return Qt::BlockingQueuedConnection; } @@ -228,7 +251,7 @@ Qt::ConnectionType blockingGUIThreadConnection() bool checkPoint(const QPoint &p, const QWidget *w) { - QWidget *atW = qApp->widgetAt(w->mapToGlobal(p)); + QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p)); if (!atW) return false; return atW->topLevelWidget() == w; } @@ -283,7 +306,7 @@ boost::filesystem::path static StartupShortcutPath() bool GetStartOnSystemStartup() { - // check for CasinoCoin.lnk + // check for Bitcoin.lnk return boost::filesystem::exists(StartupShortcutPath()); } @@ -398,7 +421,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc); if (!optionFile.good()) return false; - // Write a casinocoin.desktop file to the autostart directory: + // Write a bitcoin.desktop file to the autostart directory: optionFile << "[Desktop Entry]\n"; optionFile << "Type=Application\n"; optionFile << "Name=CasinoCoin\n"; @@ -409,10 +432,60 @@ bool SetStartOnSystemStartup(bool fAutoStart) } return true; } -#else -// TODO: OSX startup stuff; see: -// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html +#elif defined(Q_OS_MAC) +// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m + +#include +#include + +LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl); +LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl) +{ + // loop through the list of startup items and try to find the bitcoin app + CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL); + for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) { + LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i); + UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; + CFURLRef currentItemURL = NULL; + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); + if(currentItemURL && CFEqual(currentItemURL, findUrl)) { + // found + CFRelease(currentItemURL); + return item; + } + if(currentItemURL) { + CFRelease(currentItemURL); + } + } + return NULL; +} + +bool GetStartOnSystemStartup() +{ + CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); + return !!foundItem; // return boolified object +} + +bool SetStartOnSystemStartup(bool fAutoStart) +{ + CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); + + if(fAutoStart && !foundItem) { + // add bitcoin app to startup item list + LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL); + } + else if(!fAutoStart && foundItem) { + // remove item + LSSharedFileListItemRemove(loginItems, foundItem); + } + return true; +} +#else bool GetStartOnSystemStartup() { return false; } bool SetStartOnSystemStartup(bool fAutoStart) { return false; } @@ -436,7 +509,7 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) : setWindowTitle(tr("CasinoCoin-Qt")); setTextFormat(Qt::PlainText); - // setMinimumWidth is ignored for QMessageBox so put in nonbreaking spaces to make it wider. + // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider. setText(header + QString(QChar(0x2003)).repeated(50)); setDetailedText(coreOptions + "\n" + uiOptions); } @@ -445,13 +518,13 @@ void HelpMessageBox::printToConsole() { // On other operating systems, the expected action is to print the message to the console. QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions; - fprintf(stderr, "%s", strUsage.toStdString().c_str()); + fprintf(stdout, "%s", strUsage.toStdString().c_str()); } void HelpMessageBox::showOrPrint() { #if defined(WIN32) - // On windows, show a message box, as there is no stderr/stdout in windowed applications + // On Windows, show a message box, as there is no stderr/stdout in windowed applications exec(); #else // On other operating systems, print help text to console @@ -460,4 +533,3 @@ void HelpMessageBox::showOrPrint() } } // namespace GUIUtil - diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index b07c85c..738c906 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -5,6 +5,8 @@ #include #include +class SendCoinsRecipient; + QT_BEGIN_NAMESPACE class QFont; class QLineEdit; @@ -13,9 +15,8 @@ class QDateTime; class QUrl; class QAbstractItemView; QT_END_NAMESPACE -class SendCoinsRecipient; -/** Utility functions used by the CasinoCoin Qt UI. +/** Utility functions used by the Bitcoin Qt UI. */ namespace GUIUtil { @@ -23,14 +24,14 @@ namespace GUIUtil QString dateTimeStr(const QDateTime &datetime); QString dateTimeStr(qint64 nTime); - // Render CasinoCoin addresses in monospace font + // Render Bitcoin addresses in monospace font QFont bitcoinAddressFont(); // Set up widgets for address and amounts void setupAddressWidget(QLineEdit *widget, QWidget *parent); void setupAmountWidget(QLineEdit *widget, QWidget *parent); - // Parse "casinocoin:" URI into recipient object, return true on succesful parsing + // Parse "bitcoin:" URI into recipient object, return true on successful parsing // See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0 bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out); bool parseBitcoinURI(QString uri, SendCoinsRecipient *out); @@ -46,8 +47,10 @@ namespace GUIUtil @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress */ void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole); - - /** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix + + void setClipboard(const QString& str); + + /** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when no suffix is provided by the user. @param[in] parent Parent window (or 0) @@ -95,7 +98,7 @@ namespace GUIUtil bool GetStartOnSystemStartup(); bool SetStartOnSystemStartup(bool fAutoStart); - /** Help message for CasinoCoin-Qt, shown with --help. */ + /** Help message for Bitcoin-Qt, shown with --help. */ class HelpMessageBox : public QMessageBox { Q_OBJECT diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts new file mode 100644 index 0000000..86a7769 --- /dev/null +++ b/src/qt/locale/bitcoin_af_ZA.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> weergawe + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + Adres Boek + + + + Double-click to edit address or label + Dubbel-klik om die adres of etiket te wysig + + + + Create a new address + Skep 'n nuwe adres + + + + Copy the currently selected address to the system clipboard + Maak 'n kopie van die huidige adres na die stelsel klipbord + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + Teken &Boodskap + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + &Verwyder + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + Stuur &Muntstukke + + + + Export Address Book Data + Voer die Adresboek Data Uit + + + + Comma separated file (*.csv) + + + + + Error exporting + Fout uitvoering + + + + Could not write to file %1. + Kon nie na die %1 lêer skryf nie + + + + AddressTableModel + + + Label + Etiket + + + + Address + Adres + + + + (no label) + (geen etiket) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + Tik Wagwoord in + + + + New passphrase + Nuwe wagwoord + + + + Repeat new passphrase + Herhaal nuwe wagwoord + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Tik die nuwe wagwoord vir die beursie in.<br/>Gebruik asseblief 'n wagwoord van <b>ten minste 10 ewekansige karakters</b>, of <b>agt (8) of meer woorde.</b> + + + + Encrypt wallet + Enkripteer beursie + + + + This operation needs your wallet passphrase to unlock the wallet. + Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit. + + + + Unlock wallet + Sluit beursie oop + + + + This operation needs your wallet passphrase to decrypt the wallet. + Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit. + + + + Decrypt wallet + Sluit beursie oop + + + + Change passphrase + Verander wagwoord + + + + Enter the old and new passphrase to the wallet. + Tik asseblief die ou en nuwe wagwoord vir die beursie in. + + + + Confirm wallet encryption + Bevestig beursie enkripsie. + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + Die beursie is nou bewaak + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + Die beursie kon nie bewaak word nie + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Beursie bewaaking het misluk as gevolg van 'n interne fout. Die beursie is nie bewaak nie! + + + + + The supplied passphrases do not match. + Die wagwoord stem nie ooreen nie + + + + Wallet unlock failed + Beursie oopsluiting het misluk + + + + + + The passphrase entered for the wallet decryption was incorrect. + Die wagwoord wat ingetik was om die beursie oop te sluit, was verkeerd. + + + + Wallet decryption failed + Beursie dekripsie het misluk + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + Sinchroniseer met die netwerk ... + + + + &Overview + &Oorsig + + + + Show general overview of wallet + Wys algemene oorsig van die beursie + + + + &Transactions + &Transaksies + + + + Browse transaction history + Besoek transaksie geskiedenis + + + + Edit the list of stored addresses and labels + Wysig die lys van gestoorde adresse en etikette + + + + Show the list of addresses for receiving payments + Wys die lys van adresse vir die ontvangs van betalings + + + + E&xit + S&luit af + + + + Quit application + Sluit af + + + + Show information about CasinoCoin + Wys inligting oor CasinoCoin + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + &Opsies + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Beursie + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + &Lêer + + + + &Settings + &Instellings + + + + &Help + &Hulp + + + + Tabs toolbar + Blad nutsbalk + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + %1 agter + + + + Last received block was generated %1 ago. + Ontvangs van laaste blok is %1 terug. + + + + Transactions after this will not yet be visible. + + + + + Error + Fout + + + + Warning + + + + + Information + Informasie + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + Gebruik: + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + Beursie + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + S&tuur + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Die adres waarheen die betaling gestuur moet word (b.v. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Teken boodskap + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + Handtekening + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + Teken &Boodskap + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + Datum + + + + Source + + + + + Generated + + + + + + From + Van + + + + + + To + Na + + + + + own address + eie adres + + + + label + etiket + + + + + + + + Credit + Krediet + + + + matures in %n more block(s) + + + + + not accepted + nie aanvaar nie + + + + + + + Debit + Debiet + + + + Transaction fee + Transaksie fooi + + + + Net amount + Netto bedrag + + + + Message + Boodskap + + + + Comment + + + + + Transaction ID + Transaksie ID + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + Bedrag + + + + true + waar + + + + false + onwaar + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + Datum + + + + Type + Tipe + + + + Address + Adres + + + + Amount + Bedrag + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + Ontvang met + + + + Received from + + + + + Sent to + Gestuur na + + + + Payment to yourself + + + + + Mined + Gemyn + + + + (n/a) + (n.v.t) + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + Datum en tyd wat die transaksie ontvang was. + + + + Type of transaction. + Tipe transaksie. + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + Alles + + + + Today + Vandag + + + + This week + Hierdie week + + + + This month + Hierdie maand + + + + Last month + Verlede maand + + + + This year + Hierdie jaar + + + + Range... + + + + + Received with + Ontvang met + + + + Sent to + Gestuur na + + + + To yourself + Aan/na jouself + + + + Mined + Gemyn + + + + Other + Ander + + + + Enter address or label to search + + + + + Min amount + Min bedrag + + + + Copy address + Maak kopie van adres + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + Datum + + + + Type + Tipe + + + + Label + Etiket + + + + Address + Adres + + + + Amount + Bedrag + + + + ID + ID + + + + Error exporting + Fout uitvoering + + + + Could not write to file %1. + Kon nie na die %1 lêer skryf nie + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + CasinoCoin weergawe + + + + Usage: + Gebruik: + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + Fout: Hardeskyf spasie is baie laag! + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Informasie + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + Sisteem fout: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + Laai adresse... + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + Laai blok indeks... + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + Laai beursie... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + Klaar gelaai + + + + To use the %s option + + + + + Error + Fout + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts new file mode 100644 index 0000000..e2d5dfc --- /dev/null +++ b/src/qt/locale/bitcoin_ar.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + عن CasinoCoin + + + + <b>CasinoCoin</b> version + نسخة <b>CasinoCoin</b> + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + دفتر العناوين + + + + Double-click to edit address or label + أنقر على الماوس مرتين لتعديل عنوان + + + + Create a new address + قم بعمل عنوان جديد + + + + Copy the currently selected address to the system clipboard + قم بنسخ القوانين المختارة لحافظة النظام + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + &أمسح + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + + + + + Comma separated file (*.csv) + + + + + Error exporting + + + + + Could not write to file %1. + + + + + AddressTableModel + + + Label + + + + + Address + + + + + (no label) + + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + + + + + New passphrase + + + + + Repeat new passphrase + + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + + + + + Encrypt wallet + + + + + This operation needs your wallet passphrase to unlock the wallet. + + + + + Unlock wallet + + + + + This operation needs your wallet passphrase to decrypt the wallet. + + + + + Decrypt wallet + + + + + Change passphrase + + + + + Enter the old and new passphrase to the wallet. + + + + + Confirm wallet encryption + + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + + + + The supplied passphrases do not match. + + + + + Wallet unlock failed + + + + + + + The passphrase entered for the wallet decryption was incorrect. + + + + + Wallet decryption failed + + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + + + + + &Overview + + + + + Show general overview of wallet + + + + + &Transactions + + + + + Browse transaction history + + + + + Edit the list of stored addresses and labels + + + + + Show the list of addresses for receiving payments + + + + + E&xit + + + + + Quit application + + + + + Show information about CasinoCoin + + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + + + + + &Settings + + + + + &Help + + + + + Tabs toolbar + + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + + + + + Address + + + + + Amount + + + + + ID + + + + + Error exporting + + + + + Could not write to file %1. + + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 9006870..a2f79cb 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -3,116 +3,160 @@ AboutDialog - - About Bitcoin - За Биткоин + + About CasinoCoin + За CasinoCoin - - <b>Bitcoin</b> version - <b>Биткоин</b> версия + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> версия - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + +Това е експериментален софтуер. + +Разпространява се под MIT/X11 софтуерен лиценз, виж COPYING или http://www.opensource.org/licenses/mit-license.php. + +Използван е софтуер, разработен от OpenSSL Project за употреба в OpenSSL Toolkit (http://www.openssl.org/), криптографски софтуер разработен от Eric Young (eay@cryptsoft.com) и UPnP софтуер разработен от Thomas Bernard. + + + + Copyright + + + + + The CasinoCoin developers AddressBookPage - + Address Book Адреси - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Това са входящите адреси (за получаване на плащания). За прегледност може да предоставяте различен адрес за всяко плащане. - - - + Double-click to edit address or label Двоен клик за редакция на адрес или име - + Create a new address Създава нов адрес - + Copy the currently selected address to the system clipboard Копира избрания адрес - + &New Address - + &Нов адрес - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Това са вашите CasinoCoin адреси за получаване на плащания. За по-лесно проследяване на плащанията и повишена анонимност можете да използвате нов адрес за всяко плащане. + + + &Copy Address - + &Копирай - + Show &QR Code + Покажи &QR код + + + + Sign a message to prove you own a CasinoCoin address + Подпишете съобщение като доказателство, че притежавате определен адрес + + + + Sign &Message + Подпиши &съобщение + + + + Delete the currently selected address from the list + Изтрий избрания адрес от списъка + + + + Export the data in the current tab to a file + Запишете данните от текущия раздел във файл + + + + &Export - - Sign a message to prove you own this address - + + Verify a message to ensure it was signed with a specified CasinoCoin address + Проверете съобщение, за да сте сигурни че е подписано с определен CasinoCoin адрес - - &Sign Message - + + &Verify Message + &Провери съобщение - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Изтрива избрания адрес. Не могат да се изтриват входящи адреси. - - - + &Delete &Изтрий - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Копирай &име - + &Edit + &Редактирай + + + + Send &Coins - + Export Address Book Data Запазване на адреси - + Comma separated file (*.csv) CSV файл (*.csv) - + Error exporting Грешка при записа - + Could not write to file %1. Неуспешен запис в %1. @@ -120,17 +164,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Име - + Address Адрес - + (no label) (без име) @@ -138,432 +182,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase Парола - + New passphrase Нова парола - + Repeat new passphrase Още веднъж - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - Въведете нова парола за портфейла.<br/>Моля използвайте <b>поне 10 случайни символа</b>, или <b>8 или повече думи</b>. + Въведете нова парола за портфейла.<br/>Моля използвайте <b>поне 10 случайни символа</b> или <b>8 или повече думи</b>. - + Encrypt wallet Криптиране на портфейла - + This operation needs your wallet passphrase to unlock the wallet. Тази операция изисква Вашата парола за отключване на портфейла. - + Unlock wallet Отключване на портфейла - + This operation needs your wallet passphrase to decrypt the wallet. Тази операция изисква Вашата парола за декриптиране на портфейла. - + Decrypt wallet Декриптиране на портфейла - + Change passphrase - Промяна на парола + Смяна на паролата - + Enter the old and new passphrase to the wallet. Въведете текущата и новата парола за портфейла. - + Confirm wallet encryption Потвърждаване на криптирането - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ВНИМАНИЕ: Ако криптирате портфейла и забравите паролата <b>ЩЕ ЗАГУБИТЕ ВСИЧКИ КОИНИ</b>! -Сигурни ли сте, че искате да криптирате портфейла? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + - - + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted Портфейлът е криптиран - - Bitcoin 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. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed Криптирането беше неуспешно - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Криптирането на портфейла беше неуспешно поради неизвестен проблем. Портфейлът не е криптиран. - - + + The supplied passphrases do not match. Паролите не съвпадат - + Wallet unlock failed Отключването беше неуспешно - - - + + + The passphrase entered for the wallet decryption was incorrect. Паролата въведена за декриптиране на портфейла е грешна. - + Wallet decryption failed Декриптирането беше неуспешно - - Wallet passphrase was succesfully changed. - Паролата за портфейла беше променена успешно. + + Wallet passphrase was successfully changed. + Паролата на портфейла беше променена успешно. BitcoinGUI - - Bitcoin Wallet - Биткоин портфейл - - - + Sign &message... - + Подписване на &съобщение... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Синхронизиране с мрежата... - + &Overview &Баланс - + Show general overview of wallet Обобщена информация за портфейла - + &Transactions - &Плащания + &Транзакции - + Browse transaction history - История на входящи и изходящи плащания + История на входящите и изходящи транзакции - - &Address Book - &Адреси - - - + Edit the list of stored addresses and labels Редактиране на адреси - - &Receive coins - &Получаване - - - + Show the list of addresses for receiving payments - Списък на адресите за получаване на плащания + Списък на адресите за получаване - - &Send coins - &Изпращане - - - - Prove you control an address - - - - + E&xit - + Из&ход - + Quit application Затваря приложението - - &About %1 - + + Show information about CasinoCoin + Показва информация за CasinoCoin - - Show information about Bitcoin - Показва информация за Биткоин - - - + About &Qt - + За &Qt - + Show information about Qt - + &Options... &Опции... - + &Encrypt Wallet... - + &Криптиране на портфейла... - + &Backup Wallet... - + &Запазване на портфейла... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Смяна на паролата... - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... - &Запазване... - - - - Send coins to a Bitcoin address + + Reindexing blocks on disk... - - Modify configuration options for Bitcoin + + Send coins to a CasinoCoin address + Изпращане към CasinoCoin адрес + + + + Modify configuration options for CasinoCoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - Криптира или декриптира портфейла - - - + Backup wallet to another location - + Change the passphrase used for wallet encryption Променя паролата за портфейла - + &Debug window - + Open debugging and diagnostic console - + &Verify message... + &Проверка на съобщение... + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Портфейл + + + + &Send - - Verify a message signature + + &Receive - + + &Addresses + + + + + &About CasinoCoin + &За CasinoCoin + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Файл - + &Settings &Настройки - + &Help &Помощ - + Tabs toolbar Раздели - - Actions toolbar - Функции - - - - + + [testnet] [testnet] - - - Bitcoin client + + CasinoCoin client - - %n active connection(s) to Bitcoin network - %n връзка към Биткоин мрежата%n връзки към Биткоин мрежата + + %n active connection(s) to CasinoCoin network + %n връзка към CasinoCoin мрежата%n връзки към CasinoCoin мрежата - - Downloaded %1 blocks of transaction history. - %1 блока. - - - - %n second(s) ago - %n секунда%n секунди - - - - %n minute(s) ago - %n минута%n минути - - - - %n hour(s) ago - %n час%n часа - - - - %n day(s) ago - %n ден%n дни + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Синхронизиран - + Catching up... Зарежда блокове... - - Last received block was generated %1. - Последният блок е от %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Размерът на плащането ще надвиши максималният размер на безплатно плащане. Можете да платите срещу такса от %1, която ще бъде получена от участниците в мрежата, обработващи плащания. Желаете ли да платите таксата? - - - + Confirm transaction fee - + Потвърждение за такса - + Sent transaction - Изходящо плащане + Изходяща транзакция - + Incoming transaction - Входящо плащане + Входяща транзакция - + Date: %1 Amount: %2 Type: %3 @@ -572,538 +644,485 @@ Address: %4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Портфейлът е <b>криптиран</b> и <b>отключен</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Портфейлът е <b>криптиран</b> и <b>заключен</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - Показване - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Изберете мерна единица - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address Редактиране на адрес - + &Label &Име - + The label associated with this address book entry Името свързано с този запис в списъка с адреси - + &Address &Адрес - + The address associated with this address book entry. This can only be modified for sending addresses. Адресът свързан с този запис в списъка с адреси. Може да се променя само за изходящи адреси. - + New receiving address Нов адрес за получаване - + New sending address Нов адрес за изпращане - + Edit receiving address Редактиране на входящ адрес - + Edit sending address Редактиране на изходящ адрес - + The entered address "%1" is already in the address book. Вече има адрес "%1" в списъка с адреси. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + "%1" не е валиден CasinoCoin адрес. - + Could not unlock wallet. Отключването на портфейла беше неуспешно. - + New key generation failed. - Генерирането на ключ беше неуспешно. + Създаването на ключ беше неуспешно. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + Usage: - - options + + command-line options - + UI options - + UI Опции - + Set language, for example "de_DE" (default: system locale) - + Start minimized - + Show splash screen on startup (default: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Опции + + + + &Main + &Основни + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee - &Такса за изходящо плащане + &Такса за изходяща транзакция - - Main - Общи - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + + Automatically start CasinoCoin after logging in to the system. - - &Start Bitcoin on system login + + &Start CasinoCoin on system login + &Пускане на CasinoCoin при вход в системата + + + + Reset all client options to default. - - Automatically start Bitcoin after logging in to the system + + &Reset Options - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + &Мрежа - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Автоматично отваряне на входящия CasinoCoin порт. Работи само с рутери поддържащи UPnP. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - Вмъкни от клипборда - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Въведете Биткоин адрес (например 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Отваряне на входящия порт чрез &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Автоматично отваряне на входящия Bitcoin порт. Работи само с рутери поддържащи UPnP. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + - - &Connect through SOCKS4 proxy: - &Използвай SOCKS4 прокси: + + &Connect through SOCKS proxy: + - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Свързване с Биткоин мрежата чрез SOCKS4 прокси сървър (например за да анонимизирате достъпа си чрез Тор) - - - + Proxy &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) IP адрес на прокси сървъра (например 127.0.0.1) - - Port of the proxy (e.g. 1234) - Порт на прокси сървъра (например 1234) + + &Port: + - - - OptionsDialog - - Options - Опции + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + &Прозорец + + + + Show only a tray icon after minimizing the window. + След минимизиране ще е видима само иконата в системния трей. + + + + &Minimize to the tray instead of the taskbar + &Минимизиране в системния трей + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + При затваряне на прозореца приложението остава минимизирано. Ако изберете тази опция, приложението може да се затвори само чрез Изход в менюто. + + + + M&inimize on close + М&инимизиране при затваряне + + + + &Display + &Интерфейс + + + + User Interface &language: + Език: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Промяната на езика ще влезе в сила след рестартиране на CasinoCoin. + + + + &Unit to show amounts in: + Мерни единици: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Изберете единиците, показвани по подразбиране в интерфейса. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Ще се показват адресите в списъка с транзакции независимо от наличието на кратко име. + + + + &Display addresses in transaction list + Показвай и адресите в списъка с транзакции + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + Прокси адресът е невалиден. OverviewPage - + Form Форма - - - 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - + Balance: Баланс: - - Number of transactions: - Брой плащания: - - - + Unconfirmed: Непотвърдени: - + Wallet + Портфейл + + + + Immature: - - <b>Recent transactions</b> - <b>Последни плащания</b> + + Mined balance that has not yet matured + - + + <b>Recent transactions</b> + <b>Последни транзакции</b> + + + Your current balance Вашият текущ баланс - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Сборът на все още непотвърдените плащания, които не са част от текущия баланс + Сборът на все още непотвърдените транзакции, които не са част от текущия баланс - - Total number of transactions in wallet - Общ брой плащания в портфейла - - - - + + out of sync + несинхронизиран + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - - QR Code - - - - + Request Payment - + Изискай плащане - + Amount: - + Сума: - - BTC - - - - + Label: - + Име: - + Message: Съобщение: - + &Save As... - + &Запази като... - + Error encoding URI into QR Code. - + Грешка при създаването на QR Code от URI. - + + The entered amount is invalid, please check. + Въведената сума е невалидна, моля проверете. + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + PNG Images (*.png) @@ -1111,125 +1130,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Мрежа - + Number of connections - + On testnet - + Block chain - + Current number of blocks - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console + Изчисти конзолата + + + + Welcome to the CasinoCoin RPC console. - - Welcome to the Bitcoin RPC console. - - - - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Използвайте стрелки надолу и нагореза разглеждане на историятаот команди и <b>Ctrl-L</b> за изчистване на конзолата. - + Type <b>help</b> for an overview of available commands. @@ -1237,445 +1277,684 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Изпращане - + Send to multiple recipients at once Изпращане към повече от един получател - - &Add Recipient - + + Add &Recipient + Добави &получател - + Remove all transaction fields - + Изчистване на всички полета - + Clear &All - + &Изчисти - + Balance: Баланс: - + 123.456 BTC 123.456 BTC - + Confirm the send action Потвърдете изпращането - - &Send - &Изпращане + + S&end + И&зпрати - + <b>%1</b> to %2 (%3) <b>%1</b> на %2 (%3) - + Confirm send coins Потвърждаване - + Are you sure you want to send %1? Сигурни ли сте, че искате да изпратите %1? - + and и - - The recepient address is not valid, please recheck. - Адресът на получателя не е валиден, моля проверете пак. + + The recipient address is not valid, please recheck. + Невалиден адрес на получателя. - + The amount to pay must be larger than 0. Сумата трябва да е по-голяма от 0. - + The amount exceeds your balance. - + The total exceeds your balance when the %1 transaction fee is included. - + Duplicate address found, can only send to each address once per send operation. - - Error: Transaction creation failed. + + Error: Transaction creation failed! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Грешка: транзакцията беше отхвърлена. Това е възможно ако част от парите в портфейла са вече похарчени, например при паралелно използване на копие на wallet.dat SendCoinsEntry - + Form Форма - + A&mount: С&ума: - + Pay &To: Плати &На: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Въведете име за този адрес, за да го добавите в списъка с адреси - + &Label: &Име: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Адресът, към който да се направи плащането (например 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book - + Изберете от списъка с адреси - + Alt+A Alt+A - + Paste address from clipboard Вмъкни от клипборда - + Alt+P Alt+P - + Remove this recipient Махни този получател - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Въведете Биткоин адрес (например 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Въведете CasinoCoin адрес (например Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Подпиши / Провери съобщение + + + + &Sign Message + &Подпиши + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Можете да подпишете съобщение като доказателство, че притежавате определен адрес. Бъдете внимателни и не подписвайте съобщения, които биха разкрили лична информация без вашето съгласие. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Адресът, с който ще подпишете съобщението (например Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Изберете от списъка с адреси + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Вмъкни от клипборда + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Въведете съобщението тук + + + + Signature + + + + + Copy the current signature to the system clipboard + Копиране на текущия подпис + + + + Sign the message to prove you own this CasinoCoin address + Подпишете съобщение като доказателство, че притежавате определен адрес + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + &Изчисти + + + + &Verify Message + &Провери + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Адресът, с който е подписано съобщението (например Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Проверете съобщение, за да сте сигурни че е подписано с определен CasinoCoin адрес + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Въведете CasinoCoin адрес (например Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Натиснете "Подписване на съобщение" за да създадете подпис + + + + Enter CasinoCoin signature + CasinoCoin подпис + + + + + The entered address is invalid. + Въведеният адрес е невалиден. + + + + + + + Please check the address and try again. + Моля проверете адреса и опитайте отново. + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + Не е наличен частният ключ за въведеният адрес. + + + + Message signing failed. + Подписването на съобщение бе неуспешно. + + + + Message signed. + Съобщението е подписано. + + + + The signature could not be decoded. + Подписът не може да бъде декодиран. + + + + + Please check the signature and try again. + Проверете подписа и опитайте отново. + + + + The signature did not match the message digest. + Подписът не отговаря на комбинацията от съобщение и адрес. + + + + Message verification failed. + Проверката на съобщението беше неуспешна. + + + + Message verified. + Съобщението е потвърдено. + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Подлежи на промяна за %1 блока - - - + Open until %1 Подлежи на промяна до %1 - - %1/offline? - %1/офлайн? + + %1/offline + %1/офлайн - + %1/unconfirmed - %1/непотвърдено + %1/непотвърдени - + %1 confirmations - включено в %1 блока + включена в %1 блока - - <b>Status:</b> - <b>Състояние:</b> + + Status + Статус + + + + , broadcast through %n node(s) + - + + Date + Дата + + + + Source + Източник + + + + Generated + Издадени + + + + + From + От + + + + + + To + За + + + + + own address + собствен адрес + + + + label + име + + + + + + + + Credit + Кредит + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + Дебит + + + + Transaction fee + Такса + + + + Net amount + Сума нето + + + + Message + Съобщение + + + + Comment + Коментар + + + + Transaction ID + ID + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + Транзакция + + + + Inputs + + + + + Amount + Сума + + + + true + true + + + + false + false + + + , has not been successfully broadcast yet , все още не е изпратено - - - , broadcast through %1 node - , изпратено през %1 участник в мрежата + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , изпратено през %1 участници в мрежата - - - - <b>Date:</b> - <b>Дата:</b> - - - - <b>Source:</b> Generated<br> - <b>Източник:</b> Генерирани<br> - - - - - <b>From:</b> - <b>От:</b> - - - + unknown неизвестен - - - - - <b>To:</b> - <b>Към:</b> - - - - (yours, label: - (собствен, име: - - - - (yours) - (собствен) - - - - - - - <b>Credit:</b> - <b>Кредит:</b> - - - - (%1 matures in %2 more blocks) - (%1 достъпни след %2 блока) - - - - (not accepted) - (отхвърлен от мрежата) - - - - - - <b>Debit:</b> - <b>Дебит:</b> - - - - <b>Transaction fee:</b> - <b>Такса:</b> - - - - <b>Net amount:</b> - <b>Сума нето:</b> - - - - Message: - Съобщение: - - - - Comment: - Коментар: - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - - TransactionDescDialog - + Transaction details - Подробности за плащане + Транзакция - + This pane shows a detailed description of the transaction - + Описание на транзакцията TransactionTableModel - + Date Дата - + Type Тип - + Address Адрес - + Amount Сума - - Open for %n block(s) + + Open for %n more block(s) - + Open until %1 Подлежи на промяна до %1 - + Offline (%1 confirmations) - + Офлайн (%1 потвърждения) - + Unconfirmed (%1 of %2 confirmations) - + Непотвърдени (%1 от %2 потвърждения) - + Confirmed (%1 confirmations) - + Потвърдени (%1 потвърждения) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) - + This block was not received by any other nodes and will probably not be accepted! - + Блокът не е получен от останалите участници и най-вероятно няма да бъде одобрен. - + Generated but not accepted - + Received with - Получаване + Получени с - + Received from - + Sent to - Изпращане + Изпратени на - + Payment to yourself - + Mined - + Емитирани - + (n/a) - + (n/a) - + Transaction status. Hover over this field to show number of confirmations. - Състояние на плащането. Задръжте върху това поле за брой потвърждения. + Състояние на транзакцията. Задръжте върху това поле за брой потвърждения. - + Date and time that the transaction was received. Дата и час на получаване. - + Type of transaction. - Тип плащане. + Тип на транзакцията. - + Destination address of transaction. - + Получател на транзакцията. - + Amount removed from or added to balance. Сума извадена или добавена към баланса. @@ -1683,818 +1962,961 @@ Address: %4 TransactionView - - + + All - + Всички - + Today Днес - + This week Тази седмица - + This month Този месец - + Last month Предния месец - + This year Тази година - + Range... - Интервал... + От - до... - + Received with - Получаване + Получени - + Sent to - Изпращане + Изпратени на - + To yourself - + Собствени - + Mined - + Емитирани - + Other Други - + Enter address or label to search Търсене по адрес или име - + Min amount Минимална сума - + Copy address Копирай адрес - + Copy label Копирай име - + Copy amount - + + Copy transaction ID + + + + Edit label Редактирай име - + Show transaction details - + Export Transaction Data - + Comma separated file (*.csv) CSV файл (*.csv) - + Confirmed - + Потвърдени - + Date Дата - + Type Тип - + Label Име - + Address Адрес - + Amount Сума - + ID - + Error exporting Грешка при записа - + Could not write to file %1. Неуспешен запис в %1. - + Range: - + От: - + to - - - - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Копира избрания адрес - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - + до WalletModel - - Sending... - Изпращане... + + Send Coins + Изпращане - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Минимизиране в системния трей + + Export the data in the current tab to a file + Запишете данните от текущия раздел във файл - - Show only a tray icon after minimizing the window - Остава видима само иконата долу вдясно - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - При затваряне на прозореца приложението остава минимизирано. Ако изберете тази опция, приложението може да се затвори само чрез Изход в менюто. + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - + + CasinoCoin version + CasinoCoin версия - + Usage: - - Send command to -server or bitcoind + + Send command to -server or casinocoind - + List commands - + Get help for a command - + Options: + Опции: + + + + Specify configuration file (default: casinocoin.conf) - - Specify configuration file (default: bitcoin.conf) + + Specify pid file (default: casinocoind.pid) - - Specify pid file (default: bitcoind.pid) - - - - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Set database cache size in megabytes (default: 25) - - Set database disk log size in megabytes (default: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands - + Use the test network - - Output extra debugging information + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Грешка: създаването на плащане беше неуспешно - - - - Sending... - Изпращане... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Грешка: плащането беше отхвърлено. Това е възможно ако част от парите в портфейла са вече похарчени, например при паралелно използване на копие на wallet.dat - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Невалиден -tor адрес: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + Зареждане на адресите... + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + Невалиден -proxy address: '%s' + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + Зареждане на блок индекса... + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + Зареждане на портфейла... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + Преразглеждане на последовтелността от блокове... + + + + Done loading + Зареждането е завършено + + + + To use the %s option + + + + Error - + Грешка - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts new file mode 100644 index 0000000..cc78bd5 --- /dev/null +++ b/src/qt/locale/bitcoin_bs.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + O CasinoCoinu + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> verzija + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + Adresar + + + + Double-click to edit address or label + + + + + Create a new address + + + + + Copy the currently selected address to the system clipboard + + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + + + + + Comma separated file (*.csv) + + + + + Error exporting + + + + + Could not write to file %1. + + + + + AddressTableModel + + + Label + + + + + Address + + + + + (no label) + + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + + + + + New passphrase + + + + + Repeat new passphrase + + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + + + + + Encrypt wallet + + + + + This operation needs your wallet passphrase to unlock the wallet. + + + + + Unlock wallet + + + + + This operation needs your wallet passphrase to decrypt the wallet. + + + + + Decrypt wallet + + + + + Change passphrase + + + + + Enter the old and new passphrase to the wallet. + + + + + Confirm wallet encryption + + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + + + + The supplied passphrases do not match. + + + + + Wallet unlock failed + + + + + + + The passphrase entered for the wallet decryption was incorrect. + + + + + Wallet decryption failed + + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + + + + + &Overview + + + + + Show general overview of wallet + + + + + &Transactions + + + + + Browse transaction history + + + + + Edit the list of stored addresses and labels + + + + + Show the list of addresses for receiving payments + + + + + E&xit + + + + + Quit application + + + + + Show information about CasinoCoin + + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + + + + + &Settings + + + + + &Help + + + + + Tabs toolbar + + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + + + + + Address + + + + + Amount + + + + + ID + + + + + Error exporting + + + + + Could not write to file %1. + + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts new file mode 100644 index 0000000..671eb89 --- /dev/null +++ b/src/qt/locale/bitcoin_ca.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + A prop de CasinoCoin + + + + <b>CasinoCoin</b> version + + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + Llibreta d'adreçes + + + + Double-click to edit address or label + + + + + Create a new address + + + + + Copy the currently selected address to the system clipboard + Copia la selecció actual al porta-retalls del sistema + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + + + + + Comma separated file (*.csv) + + + + + Error exporting + + + + + Could not write to file %1. + + + + + AddressTableModel + + + Label + + + + + Address + + + + + (no label) + + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + + + + + New passphrase + + + + + Repeat new passphrase + + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + + + + + Encrypt wallet + + + + + This operation needs your wallet passphrase to unlock the wallet. + + + + + Unlock wallet + + + + + This operation needs your wallet passphrase to decrypt the wallet. + + + + + Decrypt wallet + + + + + Change passphrase + + + + + Enter the old and new passphrase to the wallet. + + + + + Confirm wallet encryption + + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + + + + The supplied passphrases do not match. + + + + + Wallet unlock failed + + + + + + + The passphrase entered for the wallet decryption was incorrect. + + + + + Wallet decryption failed + + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + + + + + &Overview + + + + + Show general overview of wallet + + + + + &Transactions + + + + + Browse transaction history + + + + + Edit the list of stored addresses and labels + + + + + Show the list of addresses for receiving payments + + + + + E&xit + + + + + Quit application + + + + + Show information about CasinoCoin + + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + + + + + &Settings + + + + + &Help + + + + + Tabs toolbar + + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + + + + + Address + + + + + Amount + + + + + ID + + + + + Error exporting + + + + + Could not write to file %1. + + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 40e95cd..8a84ca2 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -3,2497 +3,2915 @@ AboutDialog - - About Bitcoin - Sobre Bitcoin + + About CasinoCoin + Sobre CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versió + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versió - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + \n Aquest és software experimental.\n\n Distribuït sota llicència de software MIT/11, veure l'arxiu COPYING o http://www.opensource.org/licenses/mit-license.php.\n\nAquest producte inclou software desarrollat pel projecte OpenSSL per a l'ús de OppenSSL Toolkit (http://www.openssl.org/) i de softwqre criptogràfic escrit per l'Eric Young (eay@cryptsoft.com) i software UPnP escrit per en Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers AddressBookPage - + Address Book - llibreta d'adreces + Llibreta d'adreces - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - - - - + Double-click to edit address or label - Feu doble clic per editar la direcció o l'etiqueta + Feu doble clic per editar l'adreça o l'etiqueta - + Create a new address Crear una nova adreça - + Copy the currently selected address to the system clipboard - Copieu l'adreça seleccionada al porta-retalls del sistema + Copiar l'adreça seleccionada al porta-retalls del sistema - + &New Address - + &Nova adreça - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Aquestes són les teves adreces CasinoCoin per a rebre pagaments. Pot interesar-te proveïr diferents adreces a cadascun dels enviadors així pots identificar qui et va pagant. + + + &Copy Address - + &Copiar adreça - + Show &QR Code + Mostrar codi &QR + + + + Sign a message to prove you own a CasinoCoin address + Signa el missatge per provar que ets propietari de l'adreça CasinoCoin + + + + Sign &Message + Signar &Missatge + + + + Delete the currently selected address from the list + Esborrar l'adreça sel·leccionada + + + + Export the data in the current tab to a file - - Sign a message to prove you own this address + + &Export - - &Sign Message - + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verificar un missatge per asegurar-se que ha estat signat amb una adreça CasinoCoin específica - - Delete the currently selected address from the list. Only sending addresses can be deleted. - + + &Verify Message + &Verificar el missatge - + &Delete - &Borrar + &Esborrar - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Aquestes són la seva adreça de CasinoCoin per enviar els pagaments. Sempre revisi la quantitat i l'adreça del destinatari abans transferència de monedes. + + + Copy &Label - + Copiar &Etiqueta - + &Edit - + &Editar - + + Send &Coins + Enviar &Monedes + + + Export Address Book Data - + Exporta llibreta d'adreces - + Comma separated file (*.csv) - + Arxiu de separació per comes (*.csv) - + Error exporting - + Error en l'exportació - + Could not write to file %1. - + No s'ha pogut escriure a l'arxiu %1. AddressTableModel - + Label Etiqueta - + Address - Direcció + Adreça - + (no label) - + (sense etiqueta) AskPassphraseDialog - + Passphrase Dialog - + Dialeg de contrasenya - + Enter passphrase - + Introdueix contrasenya - + New passphrase - + Nova contrasenya - + Repeat new passphrase - + Repeteix la nova contrasenya - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - + Introdueixi la nova contrasenya al moneder<br/>Si us plau useu una contrasenya de <b>10 o més caracters aleatoris</b>, o <b>vuit o més paraules</b>. - + Encrypt wallet Xifrar la cartera - + This operation needs your wallet passphrase to unlock the wallet. - + Aquesta operació requereix la seva contrasenya del moneder per a desbloquejar-lo. - + Unlock wallet - + Desbloqueja el moneder - + This operation needs your wallet passphrase to decrypt the wallet. - + Aquesta operació requereix la seva contrasenya del moneder per a desencriptar-lo. - + Decrypt wallet - + Desencripta el moneder - + Change passphrase - + Canviar la contrasenya - + Enter the old and new passphrase to the wallet. - + Introdueixi tant l'antiga com la nova contrasenya de moneder. - + Confirm wallet encryption - + Confirmar l'encriptació del moneder - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Advertència: Si encripteu el vostre moneder i perdeu la constrasenya, <b>PERDREU TOTS ELS VOSTRES CASINOCOINS</b>! - - + + Are you sure you wish to encrypt your wallet? + Esteu segur que voleu encriptar el vostre moneder? + + + + 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. + IMPORTANT: Tota copia de seguretat que hagis realitzat hauria de ser reemplaçada pel, recentment generat, arxiu encriptat del moneder. + + + + + Warning: The Caps Lock key is on! + Advertència: Les lletres majúscules estàn activades! + + + + Wallet encrypted - + Moneder encriptat - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin es tancarà ara per acabar el procés d'encriptació. Recorda que encriptar el teu moneder no protegeix completament els teus casinocoins de ser robades per programari maliciós instal·lat al teu ordinador. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed - + L'encriptació del moneder ha fallat - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + L'encriptació del moneder ha fallat per un error intern. El seu moneder no ha estat encriptat. - - + + The supplied passphrases do not match. - + La contrasenya introduïda no coincideix. - + Wallet unlock failed - + El desbloqueig del moneder ha fallat - - - + + + The passphrase entered for the wallet decryption was incorrect. - + La contrasenya introduïda per a desencriptar el moneder és incorrecte. - + Wallet decryption failed - + La desencriptació del moneder ha fallat - - Wallet passphrase was succesfully changed. - + + Wallet passphrase was successfully changed. + La contrasenya del moneder ha estat modificada correctament. BitcoinGUI - - Bitcoin Wallet - - - - + Sign &message... - + Signar &missatge... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... - Sincronització amb la xarxa ... + Sincronitzant amb la xarxa ... - + &Overview - + &Panorama general - + Show general overview of wallet - Mostra panorama general de la cartera + Mostra panorama general del moneder - + &Transactions - + &Transaccions - + Browse transaction history Cerca a l'historial de transaccions - - &Address Book - - - - + Edit the list of stored addresses and labels Edita la llista d'adreces emmagatzemada i etiquetes - - &Receive coins - &Rebre monedes - - - + Show the list of addresses for receiving payments - + Mostra el llistat d'adreces per rebre pagaments - - &Send coins - - - - - Prove you control an address - - - - + E&xit - + S&ortir - + Quit application Sortir de l'aplicació - - &About %1 - + + Show information about CasinoCoin + Mostra informació sobre CasinoCoin - - Show information about Bitcoin - Mostra informació sobre Bitcoin - - - + About &Qt - + Sobre &Qt - + Show information about Qt - + Mostra informació sobre Qt - + &Options... - &Opcions ... + &Opcions... - + &Encrypt Wallet... - + &Xifrar moneder - + &Backup Wallet... - + &Realitzant copia de seguretat del moneder... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Canviar contrasenya... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Important blocs del disc.. - - &Export... - + + Reindexing blocks on disk... + Re-indexant blocs al disc... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Enviar monedes a una adreça CasinoCoin - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Modificar les opcions de configuració per casinocoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - - - - + Backup wallet to another location - + Realitzar còpia de seguretat del moneder a un altre directori - + Change the passphrase used for wallet encryption - + Canviar la constrasenya d'encriptació del moneder - + &Debug window - + &Finestra de debug - + Open debugging and diagnostic console - + Obrir la consola de diagnòstic i debugging - + &Verify message... - + &Verifica el missatge.. - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Moneder + + + + &Send + &Enviar + + + + &Receive + &Rebre + + + + &Addresses + &Adreces + + + + &About CasinoCoin + &Sobre CasinoCoin + + + + &Show / Hide + &Mostrar / Amagar + + + + Show or hide the main Window + Mostrar o amagar la finestra principal + + + + Encrypt the private keys that belong to your wallet + Xifrar les claus privades pertanyents al seu moneder + + + + Sign messages with your CasinoCoin addresses to prove you own them + Signa el missatges amb la seva adreça de CasinoCoin per provar que les poseeixes + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verificar els missatges per assegurar-te que han estat signades amb una adreça CasinoCoin específica. + + + &File - + &Arxiu - + &Settings - + &Configuració - + &Help &Ajuda - + Tabs toolbar - + Barra d'eines de seccions - - Actions toolbar - Accions de la barra d'eines - - - - + + [testnet] + [testnet] + + + + CasinoCoin client + Client CasinoCoin + + + + %n active connection(s) to CasinoCoin network + %n connexió activa a la xarxa CasinoCoin%n connexions actives a la xarxa CasinoCoin + + + + No block source available... - - - Bitcoin client - - - - - %n active connection(s) to Bitcoin network - + + Processed %1 of %2 (estimated) blocks of transaction history. + Processat el %1 de %2 (estimat) dels blocs del històric de transaccions. - - Downloaded %1 blocks of transaction history. - + + Processed %1 blocks of transaction history. + Proccessats %1 blocs del històric de transaccions. - - %n second(s) ago - + + %n hour(s) + %n hora%n hores - - %n minute(s) ago - + + %n day(s) + %n dia%n dies - - %n hour(s) ago - - - - - %n day(s) ago - + + %n week(s) + %n setmana%n setmanes - + + %1 behind + %1 radera + + + + Last received block was generated %1 ago. + Lúltim bloc rebut ha estat generat fa %1. + + + + Transactions after this will not yet be visible. + Les transaccions a partir d'això no seràn visibles. + + + + Error + Error + + + + Warning + Avís + + + + Information + Informació + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Aquesta transacció supera el límit de tamany. Tot i així pots enviar-la amb una comissió de %1, que es destinen als nodes que processen la seva transacció i ajuda a donar suport a la xarxa. Vols pagar la comissió? + + + Up to date Al dia - + Catching up... Posar-se al dia ... - - Last received block was generated %1. - - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - - - - + Confirm transaction fee - + Confirmar comisió de transacció - + Sent transaction Transacció enviada - + Incoming transaction - + Transacció entrant - + Date: %1 Amount: %2 Type: %3 Address: %4 - + Data: %1\nQuantitat %2\n Tipus: %3\n Adreça: %4\n - + + + URI handling + Manejant URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + la URI no pot ser processada! Això es pot ser causat per una adreça CasinoCoin invalida o paràmetres URI malformats. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - + El moneder està <b>encriptat</b> i actualment <b>desbloquejat</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> - + El moneder està <b>encriptat</b> i actualment <b>bloquejat</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ha tingut lloc un error fatal. CasinoCoin no pot continuar executant-se de manera segura i es tancará. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Alerta de xarxa EditAddressDialog - + Edit Address Editar Adreça - + &Label - + &Etiqueta - + The label associated with this address book entry - + Etiqueta associada amb aquesta entrada de la llibreta d'adreces - + &Address - + &Direcció - + The address associated with this address book entry. This can only be modified for sending addresses. - + Adreça associada amb aquesta entrada de la llibreta d'adreces. Només pot ser modificat per a enviar adreces. - + New receiving address - + Nova adreça de recepció. - + New sending address - + Nova adreça d'enviament - + Edit receiving address - + Editar adreces de recepció - + Edit sending address - + Editar adreces d'enviament - + The entered address "%1" is already in the address book. - + L'adreça introduïda "%1" ja és present a la llibreta d'adreces. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + L'adreça introduida "%1" no és una adreça CasinoCoin valida. - + Could not unlock wallet. - + No s'ha pogut desbloquejar el moneder. - + New key generation failed. - + Ha fallat la generació d'una nova clau. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versió - + Usage: - + Ús: - - options - + + command-line options + Opcions de la línia d'ordres - + UI options - + Opcions de IU - + Set language, for example "de_DE" (default: system locale) - + Definir llenguatge, per exemple "de_DE" (per defecte: Preferències locals de sistema) - + Start minimized - + Iniciar minimitzat - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - - - - - Main - - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - Port obert amb &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - - &Connect through SOCKS4 proxy: - - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - - - - - Port of the proxy (e.g. 1234) - + Mostrar finestra de benvinguda a l'inici (per defecte: 1) OptionsDialog - + Options + Opcions + + + + &Main + &Principal + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + Pay transaction &fee + Pagar &comisió de transacció + + + + Automatically start CasinoCoin after logging in to the system. + Iniciar automàticament CasinoCoin després de l'inici de sessió del sistema. + + + + &Start CasinoCoin on system login + &Iniciar CasinoCoin al inici de sessió del sistema. + + + + Reset all client options to default. + Reestablir totes les opcions del client. + + + + &Reset Options + &Reestablir Opcions + + + + &Network + &Xarxa + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Obrir el port del client de CasinoCoin al router de forma automàtica. Això només funciona quan el teu router implementa UPnP i l'opció està activada. + + + + Map port using &UPnP + Port obert amb &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Connectar a la xarxa CasinoCoin a través de un SOCKS proxy (per exemple connectant a través de Tor). + + + + &Connect through SOCKS proxy: + &Connecta a través de un proxy SOCKS: + + + + Proxy &IP: + &IP del proxy: + + + + IP address of the proxy (e.g. 127.0.0.1) + Adreça IP del proxy (per exemple 127.0.0.1) + + + + &Port: + &Port: + + + + Port of the proxy (e.g. 9050) + Port del proxy (per exemple 9050) + + + + SOCKS &Version: + &Versió de SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Versió SOCKS del proxy (per exemple 5) + + + + &Window + &Finestra + + + + Show only a tray icon after minimizing the window. + Mostrar només l'icona de la barra al minimitzar l'aplicació. + + + + &Minimize to the tray instead of the taskbar + &Minimitzar a la barra d'aplicacions + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimitza en comptes de sortir de la aplicació al tancar la finestra. Quan aquesta opció està activa, la aplicació només es tancarà al seleccionar Sortir al menú. + + + + M&inimize on close + M&inimitzar al tancar + + + + &Display + &Pantalla + + + + User Interface &language: + Llenguatge de la Interfície d'Usuari: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Aquí pots definir el llenguatge de l'aplicatiu. Aquesta configuració tindrà efecte un cop es reiniciï CasinoCoin. + + + + &Unit to show amounts in: + &Unitats per mostrar les quantitats en: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Sel·lecciona la unitat de subdivisió per defecte per mostrar en la interficie quan s'envien monedes. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Mostrar adreces CasinoCoin als llistats de transaccions o no. + + + + &Display addresses in transaction list + &Mostrar adreces al llistat de transaccions + + + + &OK + &OK + + + + &Cancel + &Cancel·la + + + + &Apply + &Aplicar + + + + default + Per defecte + + + + Confirm options reset + Confirmi el reestabliment de les opcions + + + + Some settings may require a client restart to take effect. + Algunes configuracions poden requerir reiniciar el client per a que tinguin efecte. + + + + Do you want to proceed? + Vols procedir? + + + + + Warning + Avís + + + + + This setting will take effect after restarting CasinoCoin. + Aquesta configuració tindrà efecte un cop es reiniciï CasinoCoin. + + + + The supplied proxy address is invalid. + L'adreça proxy introduïda és invalida. + OverviewPage - + Form - + Formulari - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + La informació mostrada pot no estar al día. El teu moneder es sincronitza automàticament amb la xarxa CasinoCoin un cop s'ha establert connexió, però aquest proces no s'ha completat encara. - + Balance: Balanç: - - Number of transactions: - - - - + Unconfirmed: Sense confirmar: - + Wallet - + Moneder - + + Immature: + Immatur: + + + + Mined balance that has not yet matured + Balanç minat que encara no ha madurat + + + <b>Recent transactions</b> - + <b>Transaccions recents</b> - + Your current balance El seu balanç actual - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - + Total de transaccions encara sense confirmar, que encara no es content en el balanç actual - - Total number of transactions in wallet - - - - - + + out of sync - + Fora de sincronia + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + No es pot iniciar casinocoin: manejador clicla-per-pagar QRCodeDialog - + QR Code Dialog - + Dialeg del codi QR - - QR Code - - - - + Request Payment - + Reclamar pagament - + Amount: - + Quantitat: - - BTC - - - - + Label: - + Etiqueta: - + Message: - + Missatge: - + &Save As... - + &Desar com... - + Error encoding URI into QR Code. - + Error codificant la URI en un codi QR. - + + The entered amount is invalid, please check. + La quantitat introduïda és invalida, si us plau comprovi-la. + + + Resulting URI too long, try to reduce the text for label / message. - + URI resultant massa llarga, intenta reduir el text per a la etiqueta / missatge - + Save QR Code - + Desar codi QR - + PNG Images (*.png) - + Imatges PNG (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Nom del client - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + Versió del client - + &Information - + &Informació - - Client - + + Using OpenSSL version + Utilitzant OpenSSL versió - + Startup time - + &Temps d'inici - + Network - + Xarxa - + Number of connections - + Nombre de connexions - + On testnet - + A testnet - + Block chain - + Bloquejar cadena - + Current number of blocks - + Nombre de blocs actuals - + Estimated total blocks - + Total estimat de blocs - + Last block time - + Últim temps de bloc - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Obrir - + + Command-line options + Opcions de línia d'ordres + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Mostrar el missatge d'ajuda de CasinoCoin-Qt per a obtenir un llistat de possibles ordres per a la línia d'ordres de CasinoCoin. + + + + &Show + &Mostrar + + + &Console - + &Consola - + Build date - + Data de compilació - + + CasinoCoin - Debug window + CasinoCoin -Finestra de debug + + + + CasinoCoin Core + Nucli de CasinoCoin + + + + Debug log file + Dietàri de debug + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Obrir el dietari de debug de CasinoCoin del directori de dades actual. Aixó pot trigar uns quants segons per a dietàris grossos. + + + Clear console - + Netejar consola - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Benvingut a la consola RPC de CasinoCoin - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Utilitza les fletxes d'amunt i avall per navegar per l'històric, i <b>Ctrl-L<\b> per netejar la pantalla. - + Type <b>help</b> for an overview of available commands. - + Escriu <b>help<\b> per a obtenir una llistat de les ordres disponibles. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Enviar monedes - + Send to multiple recipients at once - + Enviar a multiples destinataris al mateix temps - - &Add Recipient - + + Add &Recipient + Affegir &Destinatari - + Remove all transaction fields - + Netejar tots els camps de la transacció - + Clear &All - + Esborrar &Tot - + Balance: Balanç: - + 123.456 BTC - + 123.456 BTC - + Confirm the send action - + Confirmi l'acció d'enviament - - &Send - + + S&end + E&nviar - + <b>%1</b> to %2 (%3) - + <b>%1</b> to %2 (%3) - + Confirm send coins - + Confirmar l'enviament de monedes - + Are you sure you want to send %1? - + Estas segur que vols enviar %1? - + and - + i - - The recepient address is not valid, please recheck. - + + The recipient address is not valid, please recheck. + L'adreça remetent no és vàlida, si us plau comprovi-la. - + The amount to pay must be larger than 0. La quantitat a pagar ha de ser major que 0. - + The amount exceeds your balance. - + Import superi el saldo de la seva compte. - + The total exceeds your balance when the %1 transaction fee is included. - + El total excedeix el teu balanç quan s'afegeix la comisió a la transacció %1. - + Duplicate address found, can only send to each address once per send operation. - + S'ha trobat una adreça duplicada, tan sols es pot enviar a cada adreça un cop per ordre de enviament. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Error: La ceació de la transacció ha fallat! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Error: La transacció ha estat rebutjada. Això pot passar si alguna de les monedes del teu moneder ja s'han gastat, com si haguesis usat una copia de l'arxiu wallet.dat i s'haguessin gastat monedes de la copia però sense marcar com gastades en aquest. SendCoinsEntry - + Form - + Formulari - + A&mount: - + Q&uantitat: - + Pay &To: - + Pagar &A: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + La adreça a on envia el pagament (per exemple: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book - + Introdueixi una etiquera per a aquesta adreça per afegir-la a la llibreta d'adreces - + &Label: - + &Etiqueta: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - + Choose address from address book - + Escollir adreça del llibre d'adreces - + Alt+A - + Alta+A - + Paste address from clipboard - + Enganxar adreça del porta-retalls - + Alt+P - + Alt+P - + Remove this recipient + Eliminar aquest destinatari + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introdueixi una adreça de CasinoCoin (per exemple Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signatures .Signar/Verificar un Missatge + + + + &Sign Message + &Signar Missatge + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Pots signar missatges amb la teva adreça per provar que són teus. Sigues cautelòs al signar qualsevol cosa, ja que els atacs phising poden intentar confondre't per a que els hi signis amb la teva identitat. Tan sols signa als documents completament detallats amb els que hi estàs d'acord. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + La adreça amb la que signat els missatges (per exemple Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Escollir una adreça de la llibreta de direccions + + + + + Alt+A + Alta+A + + + + Paste address from clipboard + Enganxar adreça del porta-retalls + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Introdueix aqui el missatge que vols signar + + + + Signature + Signatura + + + + Copy the current signature to the system clipboard + Copiar la signatura actual al porta-retalls del sistema + + + + Sign the message to prove you own this CasinoCoin address + Signa el missatge per provar que ets propietari d'aquesta adreça CasinoCoin + + + + Sign &Message + Signar &Missatge + + + + Reset all sign message fields + Neteja tots els camps de clau + + + + + Clear &All + Esborrar &Tot + + + + &Verify Message + &Verificar el missatge + + + + Enter the signing 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. + Introdueixi l'adreça signant, missatge (assegura't que copies salts de línia, espais, tabuladors, etc excactament tot el text) i la signatura a sota per verificar el missatge. Per evitar ser enganyat per un atac home-entre-mig, vés amb compte de no llegir més en la signatura del que hi ha al missatge signat mateix. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + La adreça amb el que el missatge va ser signat (per exemple Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verificar el missatge per assegurar-se que ha estat signat amb una adreça CasinoCoin específica + + + + Verify &Message + Verificar &Missatge + + + + Reset all verify message fields + Neteja tots els camps de verificació de missatge + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introdueixi una adreça de CasinoCoin (per exemple Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Clica "Signar Missatge" per a generar una signatura + + + + Enter CasinoCoin signature + Introduïr una clau CasinoCoin + + + + + The entered address is invalid. + L'adreça intoduïda és invàlida. + + + + + + + Please check the address and try again. + Siu us plau, comprovi l'adreça i provi de nou. + + + + + The entered address does not refer to a key. + L'adreça introduïda no referencia a cap clau. + + + + Wallet unlock was cancelled. + El desbloqueig del moneder ha estat cancelat. + + + + Private key for the entered address is not available. + La clau privada per a la adreça introduïda no està disponible. + + + + Message signing failed. + El signat del missatge ha fallat. + + + + Message signed. + Missatge signat. + + + + The signature could not be decoded. + La signatura no s'ha pogut decodificar . + + + + + Please check the signature and try again. + Su us plau, comprovi la signatura i provi de nou. + + + + The signature did not match the message digest. + La signatura no coincideix amb el resum del missatge. + + + + Message verification failed. + Ha fallat la verificació del missatge. + + + + Message verified. + Missatge verificat. + + + + SplashScreen + + + The CasinoCoin developers - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + [testnet] TransactionDesc - - Open for %1 blocks - - - - + Open until %1 - + Obert fins %1 - - %1/offline? - + + %1/offline + %1/offline - + %1/unconfirmed - + %1/sense confirmar - + %1 confirmations - + %1 confrimacions - - <b>Status:</b> - + + Status + Estat + + + + , broadcast through %n node(s) + , difusió a través de %n node, difusió a través de %n nodes - + + Date + Data + + + + Source + Font + + + + Generated + Generat + + + + + From + Des de + + + + + + To + A + + + + + own address + Adreça pròpia + + + + label + etiqueta + + + + + + + + Credit + Crèdit + + + + matures in %n more block(s) + disponible en %n bloc mésdisponibles en %n blocs més + + + + not accepted + no acceptat + + + + + + + Debit + Dèbit + + + + Transaction fee + Comissió de transacció + + + + Net amount + Quantitat neta + + + + Message + Missatge + + + + Comment + Comentar + + + + Transaction ID + ID de transacció + + + + Generated coins must mature 120 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. + Les monedes generades han de madurar 120 blocs abans de poder ser gastades. Quan has generat aquest bloc, aquest ha estat transmés a la xarxa per a ser afegit a la cadena de blocs. Si no arriba a ser acceptat a la cadena, el seu estat passará a "no acceptat" i no podrá ser gastat. Això pot ocòrrer ocasionalment si un altre node genera un bloc a pocs segons del teu. + + + + Debug information + Informació de debug + + + + Transaction + Transacció + + + + Inputs + Entrades + + + + Amount + Quantitat + + + + true + cert + + + + false + fals + + + , has not been successfully broadcast yet - + , encara no ha estat emès correctement + + + + Open for %n more block(s) + Obre per %n bloc mésObre per %n blocs més - - , broadcast through %1 node - - - - - , broadcast through %1 nodes - - - - - <b>Date:</b> - - - - - <b>Source:</b> Generated<br> - - - - - - <b>From:</b> - - - - + unknown - - - - - - - <b>To:</b> - - - - - (yours, label: - - - - - (yours) - - - - - - - - <b>Credit:</b> - - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - - - - - - - <b>Debit:</b> - - - - - <b>Transaction fee:</b> - - - - - <b>Net amount:</b> - - - - - Message: - - - - - Comment: - - - - - Transaction ID: - - - - - Generated coins must wait 8 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - + desconegut TransactionDescDialog - + Transaction details - + Detall de la transacció - + This pane shows a detailed description of the transaction - + Aquest panell mostra una descripció detallada de la transacció TransactionTableModel - + Date - + Data - + Type - + Tipus - + Address Direcció - + Amount - + Quantitat - - Open for %n block(s) - + + Open for %n more block(s) + Obre per %n bloc mésObre per %n blocs més - + Open until %1 - + Obert fins %1 - + Offline (%1 confirmations) - + Sense connexió (%1 confirmacions) - + Unconfirmed (%1 of %2 confirmations) - + Sense confirmar (%1 de %2 confirmacions) - + Confirmed (%1 confirmations) - + Confirmat (%1 confirmacions) - - Mined balance will be available in %n more blocks - + + Mined balance will be available when it matures in %n more block(s) + El saldo recent minat estarà disponible quan venci el termini en %n bloc mésEl saldo recent minat estarà disponible quan venci el termini en %n blocs més - + This block was not received by any other nodes and will probably not be accepted! - + Aquest bloc no ha estat rebut per cap altre node i probablement no serà acceptat! - + Generated but not accepted - + Generat però no acceptat - + Received with - + Rebut amb - + Received from - + Rebut de - + Sent to - + Enviat a - + Payment to yourself - + Pagament a un mateix - + Mined - + Minat - + (n/a) - + (n/a) - + Transaction status. Hover over this field to show number of confirmations. - + Estat de la transacció. Desplaça't per aquí sobre per mostrar el nombre de confirmacions. - + Date and time that the transaction was received. - + Data i hora en que la transacció va ser rebuda. - + Type of transaction. - + Tipus de transacció. - + Destination address of transaction. - + Adreça del destinatari de la transacció. - + Amount removed from or added to balance. - + Quantitat extreta o afegida del balanç. TransactionView - - + + All - + Tot - + Today - + Avui - + This week - + Aquesta setmana - + This month - + Aquest mes - + Last month - + El mes passat - + This year - + Enguany - + Range... - + Rang... - + Received with - + Rebut amb - + Sent to - + Enviat a - + To yourself - + A tu mateix - + Mined - + Minat - + Other - + Altres - + Enter address or label to search - + Introdueix una adreça o una etiqueta per cercar - + Min amount - + Quantitat mínima - + Copy address - + Copiar adreça - + Copy label - + Copiar etiqueta - + Copy amount - + Copiar quantitat - + + Copy transaction ID + Copiar ID de transacció + + + Edit label - + Editar etiqueta - + Show transaction details - + Mostra detalls de la transacció - + Export Transaction Data - + Exportar detalls de la transacció - + Comma separated file (*.csv) - + Arxiu de separació per comes (*.csv) - + Confirmed - + Confirmat - + Date - + Data - + Type - + Tipus - + Label Etiqueta - + Address Direcció - + Amount - + Quantitat - + ID - + ID - + Error exporting - + Error en l'exportació - + Could not write to file %1. - + No s'ha pogut escriure a l'arxiu %1. - + Range: - + Rang: - + to - - - - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copieu l'adreça seleccionada al porta-retalls del sistema - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - + a WalletModel - - Sending... - L'enviament de ... + + Send Coins + Enviar monedes - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file - - Show only a tray icon after minimizing the window - + + Backup Wallet + Realitzar còpia de seguretat del moneder - - M&inimize on close - + + Wallet Data (*.dat) + Dades del moneder (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - + + Backup Failed + Còpia de seguretat faillida + + + + There was an error trying to save the wallet data to the new location. + Hi ha hagut un error intentant desar les dades del moneder al nou directori + + + + Backup Successful + Copia de seguretat realitzada correctament + + + + The wallet data was successfully saved to the new location. + Les dades del moneder han estat desades cirrectament al nou emplaçament. bitcoin-core - - Bitcoin version - + + CasinoCoin version + Versió de CasinoCoin - + Usage: - + Ús: - - Send command to -server or bitcoind - + + Send command to -server or casinocoind + Enviar comanda a -servidor o casinocoind - + List commands - + Llista d'ordres - + Get help for a command - + Obtenir ajuda per a un ordre. - + Options: - + Opcions: - - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Especificat arxiu de configuració (per defecte: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + Especificar arxiu pid (per defecte: casinocoind.pid) - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Especificar directori de dades - + Set database cache size in megabytes (default: 25) - + Establir tamany de la memoria cau en megabytes (per defecte: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Escoltar connexions a <port> (per defecte: 47950 o testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + Mantenir com a molt <n> connexions a peers (per defecte: 125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Connectar al node per obtenir les adreces de les connexions, i desconectar - + Specify your own public address - + Especificar la teva adreça pública - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Límit per a desconectar connexions errònies (per defecte: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + Nombre de segons abans de reconectar amb connexions errònies (per defecte: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Ha sorgit un error al configurar el port RPC %u escoltant a IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Escoltar connexions JSON-RPC al port <port> (per defecte: 47970 o testnet:17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Acceptar línia d'ordres i ordres JSON-RPC - + Run in the background as a daemon and accept commands - + Executar en segon pla com a programa dimoni i acceptar ordres - + Use the test network - + Usar la xarxa de prova - - Output extra debugging information - + + Accept connections from outside (default: 1 if no -proxy or -connect) + Aceptar connexions d'afora (per defecte: 1 si no -proxy o -connect) - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - - - - - Sending... - L'enviament de ... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + %s has de establir una contrasenya RPC a l'arxiu de configuració:\n%s\nEs recomana que useu la següent constrasenya aleatòria:\nrpcuser=casinocoinrpc\nrpcpassword=%s\n(no necesiteu recordar aquesta contrsenya)\nEl nom d'usuari i contrasenya NO HAN de ser els mateixos.\nSi l'arxiu no existeix, crea'l amb els permisos d'arxiu de només lectura per al propietari.\nTambé es recomana establir la notificació d'alertes i així seràs notificat de les incidències;\nper exemple: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Ha sorgit un error al configurar el port RPC %u escoltant a IPv6, retrocedint a IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Vincular a una adreça específica i sempre escoltar-hi. Utilitza la notació [host]:port per IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + No es pot bloquejar el directori de dades %s. Probablement CasinoCoin ja estigui en execució. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Error: La transacció ha estat rebutjada. Això pot passar si alguna de les monedes del teu moneder ja s'han gastat, com si haguesis usat una copia de l'arxiu wallet.dat i s'haguessin gastat monedes de la copia però sense marcar com gastades en aquest. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Error: Aquesta transacció requereix una comissió d'almenys %s degut al seu import, complexitat o per l'ús de fons recentment rebuts! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Executar ordre al rebre una alerta rellevant (%s al cmd es reemplaça per message) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Executar una ordre quan una transacció del moneder canviï (%s in cmd es canvia per TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Establir una mida màxima de transaccions d'alta prioritat/baixa comisió en bytes (per defecte: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + 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 + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Advertència: el -paytxfee és molt elevat! Aquesta és la comissió de transacció que pagaràs quan enviis una transacció. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Advertència: Les transaccions mostrades poden no ser correctes! Pot esser que necessitis actualitzar, o bé que altres nodes ho necessitin. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Advertència: Si us plau comprovi que la data i hora del seu computador siguin correctes! Si el seu rellotge està mal configurat, CasinoCoin no funcionará de manera apropiada. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Advertència: Error llegint l'arxiu wallet.dat!! Totes les claus es llegeixen correctament, però hi ha dades de transaccions o entrades del llibre d'adreces absents o bé son incorrectes. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Advertència: L'arxiu wallet.dat és corrupte, dades rescatades! L'arxiu wallet.dat original ha estat desat com wallet.{estampa_temporal}.bak al directori %s; si el teu balanç o transaccions son incorrectes hauries de restaurar-lo de un backup. + + + + Attempt to recover private keys from a corrupt wallet.dat + Intentar recuperar les claus privades d'un arxiu wallet.dat corrupte + + + + Block creation options: + Opcions de la creació de blocs: + + + + Connect only to the specified node(s) + Connectar només al(s) node(s) especificats + + + + Corrupted block database detected + S'ha detectat una base de dades de blocs corrupta + + + + Discover own IP address (default: 1 when listening and no -externalip) + Descobrir la pròpia adreça IP (per defecte: 1 quan escoltant i no -externalip) + + + + Do you want to rebuild the block database now? + Vols reconstruir la base de dades de blocs ara? + + + + Error initializing block database + Error carregant la base de dades de blocs + + + + Error initializing wallet database environment %s! + Error inicialitzant l'entorn de la base de dades del moneder %s! + + + + Error loading block database + Error carregant la base de dades del bloc + + + + Error opening block database + Error obrint la base de dades de blocs + + + + Error: Disk space is low! + Error: Espai al disc baix! + + + + Error: Wallet locked, unable to create transaction! + Error: El moneder està blocat, no és possible crear la transacció! + + + + Error: system error: + Error: error de sistema: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Error al escoltar a qualsevol port. Utilitza -listen=0 si vols això. + + + + Failed to read block info + Ha fallat la lectura de la informació del bloc + + + + Failed to read block + Ha fallat la lectura del bloc + + + + Failed to sync block index + Ha fallat la sincronització de l'índex de bloc + + + + Failed to write block index + Ha fallat la escriptura de l'índex de blocs + + + + Failed to write block info + Ha fallat la escriptura de la informació de bloc + + + + Failed to write block + Ha fallat l'escriptura del bloc + + + + Failed to write file info + Ha fallat l'escriptura de l'arxiu info + + + + Failed to write to coin database + Ha fallat l'escriptura de la basse de dades de monedes + + + + Failed to write transaction index + Ha fallat l'escriptura de l'índex de transaccions + + + + Failed to write undo data + Ha fallat el desfer de dades + + + + Find peers using DNS lookup (default: 1 unless -connect) + Cerca punts de connexió usant rastreig de DNS (per defecte: 1 tret d'usar -connect) + + + + Generate coins (default: 0) - + + How many blocks to check at startup (default: 288, 0 = all) + Quants blocs s'han de confirmar a l'inici (per defecte: 288, 0 = tots) + + + + How thorough the block verification is (0-4, default: 3) + Com verificar el bloc (0-4, per defecte 3) + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + Reconstruir l'índex de la cadena de blocs dels arxius actuals blk000??.dat + + + + Set the number of threads to service RPC calls (default: 4) + Estableix el nombre de fils per atendre trucades RPC (per defecte: 4) + + + + Verifying blocks... + Verificant blocs... + + + + Verifying wallet... + Verificant moneder... + + + + Imports blocks from external blk000??.dat file + Importa blocs de un fitxer blk000??.dat extern + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + &Informació + + + + Invalid -tor address: '%s' + Adreça -tor invàlida: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + Mantenir tot l'índex de transaccions (per defecte: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Mida màxima del buffer de recepció per a cada connexió, <n>*1000 bytes (default: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Mida màxima del buffer d'enviament per a cada connexió, <n>*1000 bytes (default: 5000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Tan sols acceptar cadenes de blocs que coincideixin amb els punts de prova (per defecte: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Només connectar als nodes de la xarxa <net> (IPv4, IPv6 o Tor) + + + + Output extra debugging information. Implies all other -debug* options + Sortida de la informació extra de debugging. Implica totes les demés opcions -debug* + + + + Output extra network debugging information + Sortida de la informació extra de debugging de xarxa. + + + + Prepend debug output with timestamp + Anteposar estampa temporal a les dades de debug + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opcions SSL: (veure la Wiki de CasinoCoin per a instruccions de configuració SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Selecciona la versió de socks proxy a utilitzar (4-5, per defecte: 5) + + + + Send trace/debug info to console instead of debug.log file + Enviar informació de traça/debug a la consola en comptes del arxiu debug.log + + + + Send trace/debug info to debugger + Enviar informació de traça/debug a un debugger + + + + Set maximum block size in bytes (default: 250000) + Establir una mida màxima de bloc en bytes (per defecte: 250000) + + + + Set minimum block size in bytes (default: 0) + Establir una mida mínima de bloc en bytes (per defecte: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Reduir l'arxiu debug.log al iniciar el client (per defecte 1 quan no -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Especificar el temps limit per a un intent de connexió en milisegons (per defecte: 5000) + + + + System error: + Error de sistema: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Utilitza UPnP per a mapejar els ports d'escolta (per defecte: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Utilitza UPnP per a mapejar els ports d'escolta (per defecte: 1 quan s'escolta) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Utilitzar proxy per arribar als serveis tor amagats (per defecte: el mateix que -proxy) + + + + Username for JSON-RPC connections + Nom d'usuari per a connexions JSON-RPC + + + + Warning + Avís + + + + Warning: This version is obsolete, upgrade required! + Advertència: Aquetsa versió està obsoleta, és necessari actualitzar! + + + + You need to rebuild the databases using -reindex to change -txindex + Necessiteu reconstruir les bases de dades usant -reindex per canviar -txindex + + + + wallet.dat corrupt, salvage failed + L'arxiu wallet.data és corrupte, el rescat de les dades ha fallat + + + + Password for JSON-RPC connections + Contrasenya per a connexions JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Permetre connexions JSON-RPC d'adreces IP específiques + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Enviar ordre al node en execució a <ip> (per defecte: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Executar orde quan el millor bloc canviï (%s al cmd es reemplaça per un bloc de hash) + + + + Upgrade wallet to latest format + Actualitzar moneder a l'últim format + + + + Set key pool size to <n> (default: 100) + Establir límit de nombre de claus a <n> (per defecte: 100) + + + + Rescan the block chain for missing wallet transactions + Re-escanejar cadena de blocs en cerca de transaccions de moneder perdudes + + + + Use OpenSSL (https) for JSON-RPC connections + Utilitzar OpenSSL (https) per a connexions JSON-RPC + + + + Server certificate file (default: server.cert) + Arxiu del certificat de servidor (per defecte: server.cert) + + + + Server private key (default: server.pem) + Clau privada del servidor (per defecte: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Xifrats acceptats (per defecte: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Aquest misatge d'ajuda + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Impossible d'unir %s a aquest ordinador (s'ha retornat l'error %d, %s) + + + + Connect through socks proxy + Connectar a través de socks proxy + + + + Allow DNS lookups for -addnode, -seednode and -connect + Permetre consultes DNS per a -addnode, -seednode i -connect + + + + Loading addresses... + Carregant adreces... + + + + Error loading wallet.dat: Wallet corrupted + Error carregant wallet.dat: Moneder corrupte + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Error carregant wallet.dat: El moneder requereix una versió de CasinoCoin més moderna + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + El moneder necesita ser re-escrit: re-inicia CasinoCoin per a completar la tasca + + + + Error loading wallet.dat + Error carregant wallet.dat + + + + Invalid -proxy address: '%s' + Adreça -proxy invalida: '%s' + + + + Unknown network specified in -onlynet: '%s' + Xarxa desconeguda especificada a -onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + S'ha demanat una versió desconeguda de -socks proxy: %i + + + + Cannot resolve -bind address: '%s' + No es pot resoldre l'adreça -bind: '%s' + + + + Cannot resolve -externalip address: '%s' + No es pot resoldre l'adreça -externalip: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Quantitat invalida per a -paytxfee=<amount>: '%s' + + + + Invalid amount + Quanitat invalida + + + + Insufficient funds + Balanç insuficient + + + + Loading block index... + Carregant índex de blocs... + + + + Add a node to connect to and attempt to keep the connection open + Afegir un node per a connectar's-hi i intentar mantenir la connexió oberta + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Impossible d'unir %s en aquest ordinador. Probablement CasinoCoin ja estigui en execució. + + + + Fee per KB to add to transactions you send + Comisió a afegir per cada KB de transaccions que enviïs + + + + Loading wallet... + Carregant moneder... + + + + Cannot downgrade wallet + No es pot reduir la versió del moneder + + + + Cannot write default address + No es pot escriure l'adreça per defecte + + + + Rescanning... + Re-escanejant... + + + + Done loading + Càrrega acabada + + + + To use the %s option + Utilitza la opció %s + + + Error - + Error - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - + Has de configurar el rpcpassword=<password> a l'arxiu de configuració:\n %s\n Si l'arxiu no existeix, crea'l amb els permís owner-readable-only. \ No newline at end of file diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 528e17a..de5592d 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - O Bitcoinu + + About CasinoCoin + O CasinoCoinu - - <b>Bitcoin</b> version - <b>Bitcoin</b> verze + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> verze - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Vývojáři Bitcoinu - + Tohle je experimentální program. -Šířen pod licencí MIT/X11, viz přiložený soubor license.txt nebo http://www.opensource.org/licenses/mit-license.php. +Šířen pod licencí MIT/X11, viz přiložený soubor COPYING nebo http://www.opensource.org/licenses/mit-license.php. Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v OpenSSL Toolkitu (http://www.openssl.org/) a kryptografický program od Erika Younga (eay@cryptsoft.com) a program UPnP od Thomase Bernarda. + + + Copyright + Copyright + + + + The CasinoCoin developers + Vývojáři CasinoCoinu + AddressBookPage - + Address Book Adresář - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Tohle jsou tvé Bitcoinové adresy pro příjem plateb. Můžeš pokaždé dát každému odesílateli jinou adresu, abys věděl, kdo ti kdy kolik platil. - - - + Double-click to edit address or label Dvojklikem myši začneš upravovat označení adresy - + Create a new address Vytvoř novou adresu - + Copy the currently selected address to the system clipboard Zkopíruj aktuálně vybranou adresu do systémové schránky - + &New Address Nová &adresa - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Tohle jsou tvé CasinoCoinové adresy pro příjem plateb. Můžeš dát pokaždé každému plátci novou adresu, abys věděl, kdo ti kdy kolik platil. + + + &Copy Address &Kopíruj adresu - + Show &QR Code Zobraz &QR kód - - Sign a message to prove you own this address - Podepiš zprávu, čímž prokážeš, že jsi vlastníkem této adresy + + Sign a message to prove you own a CasinoCoin address + Podepiš zprávu, čímž prokážeš, že jsi vlastníkem CasinoCoinové adresy - - &Sign Message + + Sign &Message Po&depiš zprávu - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Smaž aktuálně vybranou adresu ze seznamu. Smazány mohou být pouze adresy příjemců. + + Delete the currently selected address from the list + Smaž zvolenou adresu ze seznamu - + + Export the data in the current tab to a file + Exportuj data z tohoto panelu do souboru + + + + &Export + &Export + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Ověř zprávu, aby ses ujistil, že byla podepsána danou CasinoCoinovou adresou + + + + &Verify Message + &Ověř zprávu + + + &Delete S&maž - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Tohle jsou tvé CasinoCoinové adresy pro posílání plateb. Před odesláním mincí si vždy zkontroluj částku a cílovou adresu. + + + Copy &Label Kopíruj &označení - + &Edit &Uprav - + + Send &Coins + Pošli min&ce + + + Export Address Book Data Exportuj data adresáře - + Comma separated file (*.csv) CSV formát (*.csv) - + Error exporting Chyba při exportu - + Could not write to file %1. Nemohu zapisovat do souboru %1. @@ -126,17 +164,17 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open AddressTableModel - + Label Označení - + Address Adresa - + (no label) (bez označení) @@ -144,432 +182,460 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open AskPassphraseDialog - + Passphrase Dialog Změna hesla - + Enter passphrase Zadej platné heslo - + New passphrase Zadej nové heslo - + Repeat new passphrase Totéž heslo ještě jednou - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Zadej nové heslo k peněžence.<br/>Použij <b>alespoň 10 náhodných znaků</b> nebo <b>alespoň osm slov</b>. - + Encrypt wallet Zašifruj peněženku - + This operation needs your wallet passphrase to unlock the wallet. K provedení této operace musíš zadat heslo k peněžence, aby se mohla odemknout. - + Unlock wallet Odemkni peněženku - + This operation needs your wallet passphrase to decrypt the wallet. K provedení této operace musíš zadat heslo k peněžence, aby se mohla dešifrovat. - + Decrypt wallet Dešifruj peněženku - + Change passphrase Změň heslo - + Enter the old and new passphrase to the wallet. Zadej staré a nové heslo k peněžence. - + Confirm wallet encryption Potvrď zašifrování peněženky - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - VAROVÁNÍ: Pokud zašifruješ peněženku a ztratíš či zapomeneš heslo, <b>PŘIJDEŠ O VŠECHNY BITCOINY</b>! -Jsi si jistý, že chceš peněženku zašifrovat? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Varování: Pokud si zašifruješ peněženku a ztratíš či zapomeneš heslo, <b>PŘIJDEŠ O VŠECHNY CASINOCOINY</b>! - - + + Are you sure you wish to encrypt your wallet? + Jsi si jistý, že chceš peněženku zašifrovat? + + + + 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. + 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. + + + + + Warning: The Caps Lock key is on! + Upozornění: Caps Lock je zapnutý! + + + + Wallet encrypted Peněženka je zašifrována - - Bitcoin 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. - Bitcoin se teď ukončí, aby dokončil zašifrování. Pamatuj však, že pouhé zašifrování peněženky úplně nezabraňuje krádeži tvých bitcoinů malwarem, kterým se může počítač nakazit. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin se teď ukončí, aby dokončil zašifrování. Pamatuj však, že pouhé zašifrování peněženky úplně nezabraňuje krádeži tvých casinocoinů malwarem, kterým se může počítač nakazit. - - - Warning: The Caps Lock key is on. - Upozornění: Caps Lock je zapnutý. - - - - - - + + + + Wallet encryption failed Zašifrování peněženky selhalo - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Zašifrování peněženky selhalo kvůli vnitřní chybě. Tvá peněženka tedy nebyla zašifrována. - - + + The supplied passphrases do not match. Zadaná hesla nejsou shodná. - + Wallet unlock failed Odemčení peněženky selhalo - - - + + + The passphrase entered for the wallet decryption was incorrect. Nezadal jsi správné heslo pro dešifrování peněženky. - + Wallet decryption failed Dešifrování peněženky selhalo - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Heslo k peněžence bylo v pořádku změněno. BitcoinGUI - - Bitcoin Wallet - Bitcoinová peněženka - - - + Sign &message... Po&depiš zprávu... - - Show/Hide &Bitcoin - Zobrazit/Skrýt &Bitcoin - - - + Synchronizing with network... - Synchronizuji se sítí... + Synchronizuji se se sítí... - + &Overview &Přehled - + Show general overview of wallet Zobraz celkový přehled peněženky - + &Transactions &Transakce - + Browse transaction history - Procházet historii transakcí + Procházej historii transakcí - - &Address Book - &Adresář - - - + Edit the list of stored addresses and labels Uprav seznam uložených adres a jejich označení - - &Receive coins - Pří&jem mincí - - - + Show the list of addresses for receiving payments Zobraz seznam adres pro příjem plateb - - &Send coins - P&oslání mincí - - - - Prove you control an address - Prokaž vlastnictví adresy - - - + E&xit &Konec - + Quit application - Ukončit aplikaci + Ukonči aplikaci - - &About %1 - &O %1 + + Show information about CasinoCoin + Zobraz informace o CasinoCoinu - - Show information about Bitcoin - Zobraz informace o Bitcoinu - - - + About &Qt O &Qt - + Show information about Qt Zobraz informace o Qt - + &Options... &Možnosti... - + &Encrypt Wallet... Zaši&fruj peněženku... - + &Backup Wallet... - &Zazálohovat peněženku... + &Zazálohuj peněženku... - + &Change Passphrase... Změň &heslo... - - - ~%n block(s) remaining - zbývá ~%n blokzbývá ~%n blokyzbývá ~%n bloků + + + Importing blocks from disk... + Importuji bloky z disku... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Staženo %1 z %2 bloků transakční historie (%3 % hotovo). + + Reindexing blocks on disk... + Vytvářím nový index bloků na disku... - - &Export... - &Export... + + Send coins to a CasinoCoin address + Pošli mince na CasinoCoinovou adresu - - Send coins to a Bitcoin address - + + Modify configuration options for CasinoCoin + Uprav nastavení CasinoCoinu - - Modify configuration options for Bitcoin - - - - - Show or hide the Bitcoin window - Zobraz nebo skryj okno Bitcoinu - - - - Export the data in the current tab to a file - Exportovat data z tohoto panelu do souboru - - - - Encrypt or decrypt wallet - Zašifruj nebo dešifruj peněženku - - - + Backup wallet to another location Zazálohuj peněženku na jiné místo - + Change the passphrase used for wallet encryption Změň heslo k šifrování peněženky - + &Debug window - &Ladící okno + &Ladicí okno - + Open debugging and diagnostic console - Otevři ladící a diagnostickou konzoli + Otevři ladicí a diagnostickou konzoli - + &Verify message... &Ověř zprávu... - - Verify a message signature - Ověř podpis zprávy + + + CasinoCoin + CasinoCoin - + + Wallet + Peněženka + + + + &Send + &Pošli + + + + &Receive + Při&jmi + + + + &Addresses + &Adresy + + + + &About CasinoCoin + O &CasinoCoinu + + + + &Show / Hide + &Zobraz/Skryj + + + + Show or hide the main Window + Zobraz nebo skryj hlavní okno + + + + Encrypt the private keys that belong to your wallet + Zašifruj soukromé klíče ve své peněžence + + + + Sign messages with your CasinoCoin addresses to prove you own them + Podepiš zprávy svými CasinoCoinovými adresami, čímž prokážeš, že jsi jejich vlastníkem + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Ověř zprávy, aby ses ujistil, že byly podepsány danými CasinoCoinovými adresami + + + &File &Soubor - + &Settings &Nastavení - + &Help Ná&pověda - + Tabs toolbar Panel s listy - - Actions toolbar - Panel akcí - - - - + + [testnet] [testnet] - - - Bitcoin client - Bitcoin klient + + CasinoCoin client + CasinoCoin klient - - %n active connection(s) to Bitcoin network - %n aktivní spojení do Bitcoinové sítě%n aktivní spojení do Bitcoinové sítě%n aktivních spojení do Bitcoinové sítě + + %n active connection(s) to CasinoCoin network + %n aktivní spojení do CasinoCoinové sítě%n aktivní spojení do CasinoCoinové sítě%n aktivních spojení do CasinoCoinové sítě - - Downloaded %1 blocks of transaction history. - Staženo %1 bloků transakční historie. - - - - %n second(s) ago - před vteřinoupřed %n vteřinamipřed %n vteřinami - - - - %n minute(s) ago - před minutoupřed %n minutamipřed %n minutami - - - - %n hour(s) ago - před hodinoupřed %n hodinamipřed %n hodinami - - - - %n day(s) ago - včerapřed %n dnypřed %n dny + + No block source available... + Není dostupný žádný zdroj bloků... - + + Processed %1 of %2 (estimated) blocks of transaction history. + Zpracováno %1 z přibližně %2 bloků transakční historie. + + + + Processed %1 blocks of transaction history. + Zpracováno %1 bloků transakční historie. + + + + %n hour(s) + hodinu%n hodiny%n hodin + + + + %n day(s) + den%n dny%n dnů + + + + %n week(s) + týden%n týdny%n týdnů + + + + %1 behind + Stahuji ještě bloky transakcí za poslední %1 + + + + Last received block was generated %1 ago. + Poslední stažený blok byl vygenerován %1 zpátky. + + + + Transactions after this will not yet be visible. + Následné transakce ještě nebudou vidět. + + + + Error + Chyba + + + + Warning + Upozornění + + + + Information + Informace + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Tahle transakce přesahuje velikostní limit. I tak ji ale můžeš poslat, pokud za ni zaplatíš poplatek %1, který půjde uzlům, které tvou transakci zpracují, a navíc tak podpoříš síť. Chceš zaplatit poplatek? + + + Up to date - aktuální + Aktuální - + Catching up... Stahuji... - - Last received block was generated %1. - Poslední stažený blok byl vygenerován %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Tahle transakce přesahuje velikostní limit. I tak ji ale můžeš poslat, pokud za ni zaplatíš poplatek %1, který půjde uzlům, které tvou transakci zpracují, a navíc tak podpoříš síť. Chceš zaplatit poplatek? - - - + Confirm transaction fee Potvrď transakční poplatek - + Sent transaction Odeslané transakce - + Incoming transaction Příchozí transakce - + Date: %1 Amount: %2 Type: %3 @@ -582,538 +648,485 @@ Adresa: %4 - + + + URI handling + Zpracování URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + Nepodařilo se analyzovat URI! Důvodem může být neplatná CasinoCoinová adresa nebo poškozené parametry URI. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Peněženka je <b>zašifrovaná</b> a momentálně <b>odemčená</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Peněženka je <b>zašifrovaná</b> a momentálně <b>zamčená</b> - - Backup Wallet - Záloha peněženky - - - - Wallet Data (*.dat) - Data peněženky (*.dat) - - - - Backup Failed - Zálohování selhalo - - - - There was an error trying to save the wallet data to the new location. - Při ukládání peněženky na nové místo se přihodila nějaká chyba. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Stala se fatální chyba. Bitcoin nemůže bezpečně pokračovat v činnosti, a proto skončí. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Stala se fatální chyba. CasinoCoin nemůže bezpečně pokračovat v činnosti, a proto skončí. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Zobrazení - - - - default - výchozí - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - Tady lze nastavit jazyk uživatelského rozhraní. Nastavení se projeví až po restartování Bitcoinu. - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Zvol výchozí podjednotku, která se bude zobrazovat v programu a při posílání mincí - - - - &Display addresses in transaction list - &Ukazovat adresy ve výpisu transakcí - - - - Whether to show Bitcoin addresses in the transaction list - Zda ukazovat bitcoinové adresy ve výpisu transakcí nebo ne - - - - Warning - Upozornění - - - - This setting will take effect after restarting Bitcoin. - Nastavení se projeví až po restartování Bitcoinu. + Upozornění sítě EditAddressDialog - + Edit Address Uprav adresu - + &Label &Označení - + The label associated with this address book entry Označení spojené s tímto záznamem v adresáři - + &Address &Adresa - + The address associated with this address book entry. This can only be modified for sending addresses. Adresa spojená s tímto záznamem v adresáři. Lze upravovat jen pro odesílací adresy. - + New receiving address Nová přijímací adresa - + New sending address Nová odesílací adresa - + Edit receiving address Uprav přijímací adresu - + Edit sending address Uprav odesílací adresu - + The entered address "%1" is already in the address book. Zadaná adresa "%1" už v adresáři je. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Zadaná adresa "%1" není platná CasinoCoinová adresa. - + Could not unlock wallet. Nemohu odemknout peněženku. - + New key generation failed. Nepodařilo se mi vygenerovat nový klíč. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version verze - + Usage: Užití: - - options - + + command-line options + možnosti příkazové řádky - + UI options Možnosti UI - + Set language, for example "de_DE" (default: system locale) Nastavit jazyk, například "de_DE" (výchozí: systémové nastavení) - + Start minimized - Startovat minimalizovaně + Nastartovat minimalizovaně - + Show splash screen on startup (default: 1) - Zobrazovat startovací obrazovku (výchozí: 1) - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Při ukončování odpojit databáze bloků a adres. To znamená, že mohou být přesunuty do jiného adresáře, ale zpomaluje to ukončení. Peněženka je vždy odpojená. - - - - Pay transaction &fee - Platit &transakční poplatek - - - - Main - Hlavní - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Dobrovolný transakční poplatek za každý započatý kB dopomáhá k rychlému zpracování tvých transakcí. Většina transakcí má do 1 kB. Doporučená výše poplatku je 0.01. - - - - &Start Bitcoin on system login - &Spustit Bitcoin po přihlášení do systému - - - - Automatically start Bitcoin after logging in to the system - Automaticky spustí Bitcoin po přihlášení do systému - - - - &Detach databases at shutdown - Při ukončování &odpojit databáze - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Podepsáním zprávy svými adresami můžeš prokázat, že je skutečně vlastníš. Buď opatrný a nepodepisuj nic vágního; například při phishingových útocích můžeš být lákán, abys něco takového podepsal. Podepisuj pouze zcela úplná a detailní prohlášení, se kterými souhlasíš. - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresa, kterou se zpráva podepíše (např. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Vyber adresu z adresáře - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Vlož adresu ze schránky - - - - Alt+P - Alt+V - - - - Enter the message you want to sign here - Sem vepiš zprávu, kterou chceš podepsat - - - - Copy the current signature to the system clipboard - Zkopíruj aktuálně vybraný podpis do systémové schránky - - - - &Copy Signature - &Kopíruj podpis - - - - Reset all sign message fields - Vymaž všechna pole formuláře pro podepsání zrávy - - - - Clear &All - Všechno &smaž - - - - Click "Sign Message" to get signature - Kliknutím na "Podepiš zprávu" získáš podpis - - - - Sign a message to prove you own this address - Podepiš zprávu, čímž prokážeš, že jsi vlastníkem této adresy - - - - &Sign Message - &Podepiš zprávu - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Zadej Bitcoinovou adresu (např. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Chyba při podepisování - - - - %1 is not a valid address. - %1 není platná adresa. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Soukromý klíč pro %1 není dostupný. - - - - Sign failed - Podepisování selhalo - - - - NetworkOptionsPage - - - Network - Síť - - - - Map port using &UPnP - Namapovat port přes &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automaticky otevře potřebný port na routeru. Tohle funguje jen za předpokladu, že tvůj router podporuje UPnP a že je UPnP povolené. - - - - &Connect through SOCKS4 proxy: - &Připojit přes SOCKS4 proxy: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Připojí se do Bitcoinové sítě přes SOCKS4 proxy (např. když se připojuje přes Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - IP adresa proxy (např. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Port proxy (např. 1234) + Zobrazit startovací obrazovku (výchozí: 1) OptionsDialog - + Options Možnosti + + + &Main + &Hlavní + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Dobrovolný transakční poplatek za každý započatý kB dopomáhá k rychlému zpracování tvých transakcí. Většina transakcí má do 1 kB. + + + + Pay transaction &fee + Platit &transakční poplatek + + + + Automatically start CasinoCoin after logging in to the system. + Automaticky spustí CasinoCoin po přihlášení do systému. + + + + &Start CasinoCoin on system login + S&pustit CasinoCoin po přihlášení do systému + + + + Reset all client options to default. + Vrátí všechny volby na výchozí hodnoty. + + + + &Reset Options + &Obnovit nastavení + + + + &Network + &Síť + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automaticky otevře potřebný port na routeru. Tohle funguje jen za předpokladu, že tvůj router podporuje UPnP a že je UPnP povolené. + + + + Map port using &UPnP + Namapovat port přes &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Připojí se do CasinoCoinové sítě přes SOCKS proxy (např. když se připojuje přes Tor). + + + + &Connect through SOCKS proxy: + &Připojit přes SOCKS proxy: + + + + Proxy &IP: + &IP adresa proxy: + + + + IP address of the proxy (e.g. 127.0.0.1) + IP adresa proxy (např. 127.0.0.1) + + + + &Port: + Por&t: + + + + Port of the proxy (e.g. 9050) + Port proxy (např. 9050) + + + + SOCKS &Version: + &Verze SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Verze SOCKS proxy (např. 5) + + + + &Window + O&kno + + + + Show only a tray icon after minimizing the window. + Po minimalizaci okna zobrazí pouze ikonu v panelu. + + + + &Minimize to the tray instead of the taskbar + &Minimalizovávat do ikony v panelu + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Zavřením se aplikace minimalizuje. Pokud je tato volba zaškrtnuta, tak se aplikace ukončí pouze zvolením Konec v menu. + + + + M&inimize on close + Za&vřením minimalizovat + + + + &Display + Zobr&azení + + + + User Interface &language: + &Jazyk uživatelského rozhraní: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Tady lze nastavit jazyk uživatelského rozhraní. Nastavení se projeví až po restartování CasinoCoinu. + + + + &Unit to show amounts in: + J&ednotka pro částky: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Zvol výchozí podjednotku, která se bude zobrazovat v programu a při posílání mincí. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Zda ukazovat casinocoinové adresy ve výpisu transakcí nebo ne. + + + + &Display addresses in transaction list + Ukazo&vat adresy ve výpisu transakcí + + + + &OK + &Budiž + + + + &Cancel + &Zrušit + + + + &Apply + &Uložit + + + + default + výchozí + + + + Confirm options reset + Potvrzení obnovení nastavení + + + + Some settings may require a client restart to take effect. + Některá nastavení mohou vyžadovat restart klienta, aby se mohly projevit. + + + + Do you want to proceed? + Chceš pokračovat? + + + + + Warning + Upozornění + + + + + This setting will take effect after restarting CasinoCoin. + Nastavení se projeví až po restartování CasinoCoinu. + + + + The supplied proxy address is invalid. + Zadaná adresa proxy je neplatná. + OverviewPage - + Form Formulář - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Zobrazené informace nemusí být aktuální. Tvá peněženka se automaticky sesynchronizuje s CasinoCoinovou sítí, jakmile se s ní spojí. Zatím ale ještě není synchronizace dokončena. - + Balance: Stav účtu: - - Number of transactions: - Počet transakcí: - - - + Unconfirmed: Nepotvrzeno: - + Wallet Peněženka - + + Immature: + Nedozráno: + + + + Mined balance that has not yet matured + Vytěžené mince, které ještě nejsou zralé + + + <b>Recent transactions</b> <b>Poslední transakce</b> - + Your current balance Aktuální stav tvého účtu - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Celkem z transakcí, které ještě nejsou potvrzené a které se ještě nezapočítávají do celkového stavu účtu - - Total number of transactions in wallet - Celkový počet transakcí v peněžence - - - - + + out of sync - + nesynchronizováno + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Nemůžu spustit casinocoin: obsluha click-to-pay QRCodeDialog - + QR Code Dialog QR kód - - QR Code - QR kód - - - + Request Payment Požadovat platbu - + Amount: Částka: - - BTC - BTC - - - + Label: Označení: - + Message: Zpráva: - + &Save As... &Ulož jako... - + Error encoding URI into QR Code. Chyba při kódování URI do QR kódu. - + + The entered amount is invalid, please check. + Zadaná částka je neplatná, překontroluj ji prosím. + + + Resulting URI too long, try to reduce the text for label / message. Výsledná URI je příliš dlouhá, zkus zkrátit text označení / zprávy. - + Save QR Code Ulož QR kód - + PNG Images (*.png) PNG obrázky (*.png) @@ -1121,453 +1134,713 @@ Adresa: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Název klienta - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + Verze klienta - + &Information - + &Informace - - Client - + + Using OpenSSL version + Používaná verze OpenSSL - + Startup time - + Čas spuštění - + Network Síť - + Number of connections - + Počet spojení - + On testnet - + V testnetu - + Block chain - + Řetězec bloků - + Current number of blocks - + Aktuální počet bloků - + Estimated total blocks - + Odhad celkového počtu bloků - + Last block time - + Čas posledního bloku - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Otevřít - + + Command-line options + Argumenty z příkazové řádky + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Seznam parametrů CasinoCoinu pro příkazovou řádku získáš v nápovědě CasinoCoinu Qt. + + + + &Show + &Zobrazit + + + &Console - + &Konzole - + Build date - + Datum kompilace - + + CasinoCoin - Debug window + CasinoCoin - ladicí okno + + + + CasinoCoin Core + Jádro CasinoCoinu + + + + Debug log file + Soubor s ladicími záznamy + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Otevři soubor s ladicími záznamy CasinoCoinu z aktuálního datového adresáře. U velkých logů to může pár vteřin zabrat. + + + Clear console - + Vyčistit konzoli - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Vítej v CasinoCoinové RPC konzoli. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + V historii se pohybuješ šipkami nahoru a dolů a pomocí <b>Ctrl-L</b> čistíš obrazovku. - + Type <b>help</b> for an overview of available commands. - + Napsáním <b>help</b> si vypíšeš přehled dostupných příkazů. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Pošli mince - + Send to multiple recipients at once Pošli více příjemcům naráz - - &Add Recipient + + Add &Recipient Při&dej příjemce - + Remove all transaction fields Smaž všechny transakční formuláře - + Clear &All - Všechno &smaž + Všechno s&maž - + Balance: Stav účtu: - + 123.456 BTC 123.456 BTC - + Confirm the send action Potvrď odeslání - - &Send - &Pošli + + S&end + P&ošli - + <b>%1</b> to %2 (%3) <b>%1</b> pro %2 (%3) - + Confirm send coins Potvrď odeslání mincí - + Are you sure you want to send %1? Jsi si jistý, že chceš poslat %1? - + and a - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Adresa příjemce je neplatná, překontroluj ji prosím. - + The amount to pay must be larger than 0. Odesílaná částka musí být větší než 0. - + The amount exceeds your balance. Částka překračuje stav účtu. - + The total exceeds your balance when the %1 transaction fee is included. Celková částka při připočítání poplatku %1 překročí stav účtu. - + Duplicate address found, can only send to each address once per send operation. Zaznamenána duplikovaná adresa; každá adresa může být v odesílané platbě pouze jednou. - - Error: Transaction creation failed. - Chyba: Vytvoření transakce selhalo. + + Error: Transaction creation failed! + Chyba: Vytvoření transakce selhalo! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Chyba Transakce byla odmítnuta. Tohle může nastat, pokud nějaké mince z tvé peněženky už jednou byly utraceny, například pokud používáš kopii souboru wallet.dat a mince byly utraceny v druhé kopii, ale nebyly označeny jako utracené v této. + Chyba: Transakce byla odmítnuta. Tohle může nastat, pokud nějaké mince z tvé peněženky už jednou byly utraceny, například pokud používáš kopii souboru wallet.dat a mince byly utraceny v druhé kopii, ale nebyly označeny jako utracené v této. SendCoinsEntry - + Form Formulář - + A&mount: - Čá&stka: + Čás&tka: - + Pay &To: &Komu: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adresa příjemce (např. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Zadej označení této adresy; obojí se ti pak uloží do adresáře - + &Label: - &Označení: + O&značení: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresa příjemce (např. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Vyber adresu z adresáře - + Alt+A Alt+A - + Paste address from clipboard Vlož adresu ze schránky - + Alt+P Alt+P - + Remove this recipient Smaž tohoto příjemce - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Zadej Bitcoinovou adresu (např. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Zadej CasinoCoinovou adresu (např. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Podpisy - podepsat/ověřit zprávu + + + + &Sign Message + &Podepiš zprávu + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Podepsáním zprávy svými adresami můžeš prokázat, že je skutečně vlastníš. Buď opatrný a nepodepisuj nic vágního; například při phishingových útocích můžeš být lákán, abys něco takového podepsal. Podepisuj pouze zcela úplná a detailní prohlášení, se kterými souhlasíš. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adresa, kterou se zpráva podepíše (např. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Vyber adresu z adresáře + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Vlož adresu ze schránky + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Sem vepiš zprávu, kterou chceš podepsat + + + + Signature + Podpis + + + + Copy the current signature to the system clipboard + Zkopíruj aktuálně vybraný podpis do systémové schránky + + + + Sign the message to prove you own this CasinoCoin address + Podepiš zprávu, čímž prokážeš, že jsi vlastníkem této CasinoCoinové adresy + + + + Sign &Message + Po&depiš zprávu + + + + Reset all sign message fields + Vymaž všechna pole formuláře pro podepsání zrávy + + + + + Clear &All + Všechno &smaž + + + + &Verify Message + &Ověř zprávu + + + + Enter the signing 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. + K ověření podpisu zprávy zadej podepisující adresu, zprávu (ověř si, že správně kopíruješ zalomení řádků, mezery, tabulátory apod.) a podpis. Dávej pozor na to, abys nezkopíroval do podpisu víc, než co je v samotné podepsané zprávě, abys nebyl napálen man-in-the-middle útokem. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adresa, kterou je zpráva podepsána (např. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Ověř zprávu, aby ses ujistil, že byla podepsána danou CasinoCoinovou adresou + + + + Verify &Message + O&věř zprávu + + + + Reset all verify message fields + Vymaž všechna pole formuláře pro ověření zrávy + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Zadej CasinoCoinovou adresu (např. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Kliknutím na "Podepiš zprávu" vygeneruješ podpis + + + + Enter CasinoCoin signature + Vlož CasinoCoinový podpis + + + + + The entered address is invalid. + Zadaná adresa je neplatná. + + + + + + + Please check the address and try again. + Zkontroluj ji prosím a zkus to pak znovu. + + + + + The entered address does not refer to a key. + Zadaná adresa nepasuje ke klíči. + + + + Wallet unlock was cancelled. + Odemčení peněženky bylo zrušeno. + + + + Private key for the entered address is not available. + Soukromý klíč pro zadanou adresu není dostupný. + + + + Message signing failed. + Podepisování zprávy selhalo. + + + + Message signed. + Zpráv podepsána. + + + + The signature could not be decoded. + Podpis nejde dekódovat. + + + + + Please check the signature and try again. + Zkontroluj ho prosím a zkus to pak znovu. + + + + The signature did not match the message digest. + Podpis se neshoduje s hašem zprávy. + + + + Message verification failed. + Ověřování zprávy selhalo. + + + + Message verified. + Zpráva ověřena. + + + + SplashScreen + + + The CasinoCoin developers + Vývojáři CasinoCoinu + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Otevřeno pro %1 bloků - - - + Open until %1 Otřevřeno dokud %1 - - %1/offline? - %1/offline? + + %1/offline + %1/offline - + %1/unconfirmed %1/nepotvrzeno - + %1 confirmations %1 potvrzení - - <b>Status:</b> - <b>Stav:</b> + + Status + Stav + + + + , broadcast through %n node(s) + , rozesláno přes 1 uzel, rozesláno přes %n uzly, rozesláno přes %n uzlů - + + Date + Datum + + + + Source + Zdroj + + + + Generated + Vygenerováno + + + + + From + Od + + + + + + To + Pro + + + + + own address + vlastní adresa + + + + label + označení + + + + + + + + Credit + Příjem + + + + matures in %n more block(s) + dozraje po jednom blokudozraje po %n blocíchdozraje po %n blocích + + + + not accepted + neakceptováno + + + + + + + Debit + Výdaj + + + + Transaction fee + Transakční poplatek + + + + Net amount + Čistá částka + + + + Message + Zpráva + + + + Comment + Komentář + + + + Transaction ID + ID transakce + + + + Generated coins must mature 120 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. + Vygenerované mince musí čekat 120 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. + + + + Debug information + Ladicí informace + + + + Transaction + Transakce + + + + Inputs + Vstupy + + + + Amount + Částka + + + + true + true + + + + false + false + + + , has not been successfully broadcast yet , ještě nebylo rozesláno - - - , broadcast through %1 node - , rozesláno přes %1 uzel + + + Open for %n more block(s) + Otevřeno pro 1 další blokOtevřeno pro %n další blokyOtevřeno pro %n dalších bloků - - , broadcast through %1 nodes - , rozesláno přes %1 uzlů - - - - <b>Date:</b> - <b>Datum:</b> - - - - <b>Source:</b> Generated<br> - <b>Zdroj:</b> Vygenerováno<br> - - - - - <b>From:</b> - <b>Od:</b> - - - + unknown neznámo - - - - - <b>To:</b> - <b>Pro:</b> - - - - (yours, label: - (tvoje, označení: - - - - (yours) - (tvoje) - - - - - - - <b>Credit:</b> - <b>Příjem:</b> - - - - (%1 matures in %2 more blocks) - (%1 dozraje po %2 blocích) - - - - (not accepted) - (neakceptováno) - - - - - - <b>Debit:</b> - <b>Výdaj:</b> - - - - <b>Transaction fee:</b> - <b>Transakční poplatek:</b> - - - - <b>Net amount:</b> - <b>Čistá částka:</b> - - - - Message: - Zpráva: - - - - Comment: - Komentář: - - - - Transaction ID: - ID transakce: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Vygenerované mince musí čekat 120 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. Občas se to může stát, když jiný uzel vygeneruje blok zhruba ve stejném okamžiku jako ty. - TransactionDescDialog - + Transaction details Detaily transakce - + This pane shows a detailed description of the transaction Toto okno zobrazuje detailní popis transakce @@ -1575,117 +1848,117 @@ Adresa: %4 TransactionTableModel - + Date Datum - + Type Typ - + Address Adresa - + Amount Částka - - Open for %n block(s) - Otevřeno pro 1 blokOtevřeno pro %n blokyOtevřeno pro %n bloků + + Open for %n more block(s) + Otevřeno pro 1 další blokOtevřeno pro %n další blokyOtevřeno pro %n dalších bloků - + Open until %1 Otřevřeno dokud %1 - + Offline (%1 confirmations) Offline (%1 potvrzení) - + Unconfirmed (%1 of %2 confirmations) Nepotvrzeno (%1 z %2 potvrzení) - + Confirmed (%1 confirmations) Potvrzeno (%1 potvrzení) - - Mined balance will be available in %n more blocks - Vytěžené mince budou použitelné po jednom blokuVytěžené mince budou použitelné po %n blocíchVytěžené mince budou použitelné po %n blocích + + Mined balance will be available when it matures in %n more block(s) + Vytěžené mince budou použitelné po dozrání, tj. po jednom blokuVytěžené mince budou použitelné po dozrání, tj. po %n blocíchVytěžené mince budou použitelné po dozrání, tj. po %n blocích - + This block was not received by any other nodes and will probably not be accepted! Tento blok nedostal žádný jiný uzel a pravděpodobně nebude akceptován! - + Generated but not accepted Vygenerováno, ale neakceptováno - + Received with Přijato do - + Received from Přijato od - + Sent to Posláno na - + Payment to yourself Platba sama sobě - + Mined Vytěženo - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. Stav transakce. Najetím myši na toto políčko si zobrazíš počet potvrzení. - + Date and time that the transaction was received. Datum a čas přijetí transakce. - + Type of transaction. Druh transakce. - + Destination address of transaction. Cílová adresa transakce. - + Amount removed from or added to balance. Částka odečtená z nebo přičtená k účtu. @@ -1693,817 +1966,967 @@ Adresa: %4 TransactionView - - + + All Vše - + Today Dnes - + This week Tento týden - + This month Tento měsíc - + Last month Minulý měsíc - + This year Letos - + Range... Rozsah... - + Received with Přijato - + Sent to Posláno - + To yourself Sám sobě - + Mined Vytěženo - + Other Ostatní - + Enter address or label to search Zadej adresu nebo označení pro její vyhledání - + Min amount Minimální částka - + Copy address Kopíruj adresu - + Copy label Kopíruj její označení - + Copy amount Kopíruj částku - + + Copy transaction ID + Kopíruj ID transakce + + + Edit label Uprav označení - + Show transaction details Zobraz detaily transakce - + Export Transaction Data Exportuj transakční data - + Comma separated file (*.csv) CSV formát (*.csv) - + Confirmed Potvrzeno - + Date Datum - + Type Typ - + Label Označení - + Address Adresa - + Amount Částka - + ID ID - + Error exporting Chyba při exportu - + Could not write to file %1. Nemohu zapisovat do souboru %1. - + Range: Rozsah: - + to - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopírovat aktuálně vybrané adresy do schránky - - - - &Copy Address - &Kopíruj adresu - - - - Reset all verify message fields - - - - - Clear &All - Všechno &smaž - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Posílám... + + Send Coins + Pošli mince - WindowOptionsPage + WalletView - - Window - + + &Export + &Export - - &Minimize to the tray instead of the taskbar - &Minimalizovat do systémové lišty namísto do hlavního panelu + + Export the data in the current tab to a file + Exportuj data z tohoto panelu do souboru - - Show only a tray icon after minimizing the window - Po minimalizaci okna zobrazovat pouze ikonu v systémové liště + + Backup Wallet + Záloha peněženky - - M&inimize on close - + + Wallet Data (*.dat) + Data peněženky (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - + + Backup Failed + Zálohování selhalo + + + + There was an error trying to save the wallet data to the new location. + Při ukládání peněženky na nové místo se přihodila nějaká chyba. + + + + Backup Successful + Úspěšně zazálohováno + + + + The wallet data was successfully saved to the new location. + Data z peněženky byla v pořádku uložena na nové místo. bitcoin-core - - Bitcoin version - Verze Bitcoinu + + CasinoCoin version + Verze CasinoCoinu - + Usage: Užití: - - Send command to -server or bitcoind - Poslat příkaz pro -server nebo bitcoind + + Send command to -server or casinocoind + Poslat příkaz pro -server nebo casinocoind - + List commands Výpis příkazů - + Get help for a command Získat nápovědu pro příkaz - + Options: Možnosti: - - Specify configuration file (default: bitcoin.conf) - Konfigurační soubor (výchozí: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Konfigurační soubor (výchozí: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - PID soubor (výchozí: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + PID soubor (výchozí: casinocoind.pid) - - Generate coins - Generovat mince - - - - Don't generate coins - Negenerovat mince - - - + Specify data directory Adresář pro data - + Set database cache size in megabytes (default: 25) Nastavit velikost databázové vyrovnávací paměti v megabajtech (výchozí: 25) - - Set database disk log size in megabytes (default: 100) - Nastavit velikost databázového souboru s logy v megabajtech (výchozí: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Čekat na spojení na <portu> (výchozí: 47950 nebo testnet: 17950) - - Specify connection timeout (in milliseconds) - Zadej časový limit spojení (v milisekundách) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Čekat na spojení na <portu> (výchozí: 8333 nebo testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) - Povol nejvýše <n> připojení k uzlům (výchozí: 125) + Povolit nejvýše <n> připojení k uzlům (výchozí: 125) - - Connect only to the specified node - Připojovat se pouze k udanému uzlu - - - + Connect to a node to retrieve peer addresses, and disconnect - + Připojit se k uzlu, získat adresy jeho protějšků a odpojit se - + Specify your own public address - + Specifikuj svou veřejnou adresu - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - Práh pro odpojování nesprávně se chovajících uzlů (výchozí: 100) + Práh pro odpojování zlobivých uzlů (výchozí: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - Doba ve vteřinách, po kterou se nebudou moci nesprávně se chovající uzly znovu připojit (výchozí: 86400) + Doba ve vteřinách, po kterou se nebudou moci zlobivé uzly znovu připojit (výchozí: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maximální velikost přijímacího bufferu pro každé spojení, <n>*1000 bytů (výchozí: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Při nastavování naslouchacího RPC portu %i pro IPv4 nastala chyba: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maximální velikost odesílacího bufferu pro každé spojení, <n>*1000 bytů (výchozí: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Čekat na JSON RPC spojení na <portu> (výchozí: 47970 nebo testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Akceptovat příkazy z příkazové řádky a přes JSON-RPC - + Run in the background as a daemon and accept commands Běžet na pozadí jako démon a akceptovat příkazy - + Use the test network Použít testovací síť (testnet) - - Output extra debugging information - Tisknout speciální ladící informace + + Accept connections from outside (default: 1 if no -proxy or -connect) + Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, musíš nastavit rpcpassword v konfiguračním souboru: +%s +Je vhodné použít následující náhodné heslo: +rpcuser=casinocoinrpc +rpcpassword=%s +(není potřeba si ho pamatovat) +rpcuser a rpcpassword NESMÍ být stejné. +Pokud konfigurační soubor ještě neexistuje, vytvoř ho tak, aby ho mohl číst pouze vlastník. +Je také doporučeno si nastavit alertnotify, abys byl upozorněn na případné problémy; +například: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Při nastavování naslouchacího RPC portu %u pro IPv6 nastala chyba, vracím se k IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Poslouchat na zadané adrese. Pro zápis IPv6 adresy použij notaci [adresa]:port + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Nedaří se mi získat zámek na datový adresář %s. CasinoCoin pravděpodobně už jednou běží. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Chyba: Transakce byla odmítnuta! Tohle může nastat, pokud nějaké mince z tvé peněženky už jednou byly utraceny, například pokud používáš kopii souboru wallet.dat a mince byly utraceny v druhé kopii, ale nebyly označeny jako utracené v této. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Chyba: Tahle transakce vyžaduje transakční poplatek nejméně %s kvůli velikosti zasílané částky, komplexnosti nebo použití nedávno přijatých mincí! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Spustit příkaz po přijetí relevantního hlášení (%s se v příkazu nahradí za zprávu) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Spustit příkaz, když se objeví transakce týkající se peněženky (%s se v příkazu nahradí za TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Nastavit maximální velikost prioritních/nízkopoplatkových transakcí v bajtech (výchozí: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Tohle je testovací verze – používej ji jen na vlastní riziko, ale rozhodně ji nepoužívej k těžbě nebo pro obchodní aplikace + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Upozornění: -paytxfee je nastaveno velmi vysoko! Toto je transakční poplatek, který zaplatíš za každou poslanou transakci. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Upozornění: Zobrazené transakce nemusí být správné! Možná potřebuješ aktualizovat nebo ostatní uzly potřebují aktualizovat. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Upozornění: Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, CasinoCoin nebude fungovat správně. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Upozornění: nastala chyba při čtení souboru wallet.dat! 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é. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Upozornění: soubor wallet.dat je poškozený, data jsou však zachráněna! Původní soubor wallet.dat je uložený jako wallet.{timestamp}.bak v %s. Pokud je stav tvého účtu nebo transakce nesprávné, zřejmě bys měl obnovit zálohu. + + + + Attempt to recover private keys from a corrupt wallet.dat + Pokusit se zachránit soukromé klíče z poškozeného souboru wallet.dat + + + + Block creation options: + Možnosti vytvoření bloku: + + + + Connect only to the specified node(s) + Připojit se pouze k zadanému uzlu (příp. zadaným uzlům) + + + + Corrupted block database detected + Bylo zjištěno poškození databáze bloků + + + + Discover own IP address (default: 1 when listening and no -externalip) + Zjistit vlastní IP adresu (výchozí: 1, pokud naslouchá a není zadáno -externalip) + + + + Do you want to rebuild the block database now? + Chceš přestavět databázi bloků hned teď? + + + + Error initializing block database + Chyba při zakládání databáze bloků + + + + Error initializing wallet database environment %s! + Chyba při vytváření databázového prostředí %s pro peněženku! + + + + Error loading block database + Chyba při načítání databáze bloků + + + + Error opening block database + Chyba při otevírání databáze bloků + + + + Error: Disk space is low! + Problém: Na disku je málo místa! + + + + Error: Wallet locked, unable to create transaction! + Chyba: Peněženka je zamčená, nemohu vytvořit transakci! + + + + Error: system error: + Chyba: systémová chyba: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Nepodařilo se naslouchat na žádném portu. Použij -listen=0, pokud to byl tvůj záměr. + + + + Failed to read block info + Nepodařilo se přečíst informace o bloku + + + + Failed to read block + Nepodařilo se přečíst blok + + + + Failed to sync block index + Nepodařilo se sesynchronizovat index bloků + + + + Failed to write block index + Nepodařilo se zapsat index bloků + + + + Failed to write block info + Nepodařilo se zapsat informace o bloku + + + + Failed to write block + Nepodařilo se zapsat blok + + + + Failed to write file info + Nepodařilo se zapsat informace o souboru + + + + Failed to write to coin database + Selhal zápis do databáze mincí + + + + Failed to write transaction index + Nepodařilo se zapsat index transakcí + + + + Failed to write undo data + Nepodařilo se zapsat data o vracení změn + + + + Find peers using DNS lookup (default: 1 unless -connect) + Hledat uzly přes DNS (výchozí: 1, pokud není zadáno -connect) + + + + Generate coins (default: 0) + Generovat mince (výchozí: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Kolik bloků při startu zkontrolovat (výchozí: 288, 0 = všechny) + + + + How thorough the block verification is (0-4, default: 3) + Jak moc důkladná má být verifikace bloků (0-4, výchozí: 3) + + + + Not enough file descriptors available. + Je nedostatek deskriptorů souborů. + + + + Rebuild block chain index from current blk000??.dat files + Znovu vytvořit index řetězce bloků z aktuálních blk000??.dat souborů + + + + Set the number of threads to service RPC calls (default: 4) + Nastavení počtu vláken pro servisní RPC volání (výchozí: 4) + + + + Verifying blocks... + Ověřuji bloky... + + + + Verifying wallet... + Kontroluji peněženku... + + + + Imports blocks from external blk000??.dat file + Importovat bloky z externího souboru blk000??.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Nastavení počtu vláken pro verifikaci skriptů (max. 16, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: 0) + + + + Information + Informace + + + + Invalid -tor address: '%s' + Neplatná -tor adresa: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Neplatná částka pro -minrelaytxfee=<částka>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Neplatná částka pro -mintxfee=<částka>: '%s' + + + + Maintain a full transaction index (default: 0) + Spravovat úplný index transakcí (výchozí: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maximální velikost přijímacího bufferu pro každé spojení, <n>*1000 bajtů (výchozí: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maximální velikost odesílacího bufferu pro každé spojení, <n>*1000 bajtů (výchozí: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Uznávat pouze řetěz bloků, který odpovídá vnitřním kontrolním bodům (výchozí: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Připojit se pouze k uzlům v <net> síti (IPv4, IPv6 nebo Tor) + + + + Output extra debugging information. Implies all other -debug* options + Tisknout speciální ladicí informace. Implikuje použití všech -debug* voleb + + + + Output extra network debugging information + Tisknout speciální ladicí informace o síti + + + Prepend debug output with timestamp - Připojit před ladící výstup časové razítko + Připojit před ladicí výstup časové razítko - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Možnosti SSL: (viz instrukce nastavení SSL v CasinoCoin Wiki) + + + + Select the version of socks proxy to use (4-5, default: 5) + Zvol verzi socks proxy (4-5, výchozí: 5) + + + Send trace/debug info to console instead of debug.log file - Posílat stopovací/ladící informace do konzole místo do souboru debug.log + Posílat stopovací/ladicí informace do konzole místo do souboru debug.log - + Send trace/debug info to debugger - Posílat stopovací/ladící informace do debuggeru + Posílat stopovací/ladicí informace do debuggeru - + + Set maximum block size in bytes (default: 250000) + Nastavit maximální velikost bloku v bajtech (výchozí: 250000) + + + + Set minimum block size in bytes (default: 0) + Nastavit minimální velikost bloku v bajtech (výchozí: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Při spuštění klienta zmenšit soubor debug.log (výchozí: 1, pokud není zadáno -debug) + + + + Signing transaction failed + Podepisování transakce selhalo + + + + Specify connection timeout in milliseconds (default: 5000) + Zadej časový limit spojení v milisekundách (výchozí: 5000) + + + + System error: + Systémová chyba: + + + + Transaction amount too small + Částka v transakci je příliš malá + + + + Transaction amounts must be positive + Částky v transakci musí být kladné + + + + Transaction too large + Transace je příliš velká + + + + Use UPnP to map the listening port (default: 0) + Použít UPnP k namapování naslouchacího portu (výchozí: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Použít UPnP k namapování naslouchacího portu (výchozí: 1, pokud naslouchá) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Použít proxy k připojení ke skryté služby (výchozí: stejné jako -proxy) + + + Username for JSON-RPC connections Uživatelské jméno pro JSON-RPC spojení - + + Warning + Upozornění + + + + Warning: This version is obsolete, upgrade required! + Upozornění: tahle verze je zastaralá, měl bys ji aktualizovat! + + + + You need to rebuild the databases using -reindex to change -txindex + Je třeba přestavět databázi použitím -reindex, aby bylo možné změnit -txindex + + + + wallet.dat corrupt, salvage failed + Soubor wallet.dat je poškozen, jeho záchrana se nezdařila + + + Password for JSON-RPC connections Heslo pro JSON-RPC spojení - - Listen for JSON-RPC connections on <port> (default: 8332) - Čekat na JSON-RPC spojení na <portu> (výchozí: 8332) - - - + Allow JSON-RPC connections from specified IP address Povolit JSON-RPC spojení ze specifikované IP adresy - + Send commands to node running on <ip> (default: 127.0.0.1) Posílat příkazy uzlu běžícím na <ip> (výchozí: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Spustit příkaz, když se změní nejlepší blok (%s se v příkazu nahradí hashem bloku) - + Upgrade wallet to latest format Převést peněženku na nejnovější formát - + Set key pool size to <n> (default: 100) Nastavit zásobník klíčů na velikost <n> (výchozí: 100) - + Rescan the block chain for missing wallet transactions Přeskenovat řetězec bloků na chybějící transakce tvé pěněženky - - How many blocks to check at startup (default: 2500, 0 = all) - Kolik bloků při startu zkontrolovat (výchozí: 2500, 0 = všechny) - - - - How thorough the block verification is (0-6, default: 1) - Jak moc důkladná má verifikace bloků být (0-6, výchozí: 1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Možnosti SSL: (viz instrukce nastavení SSL v Bitcoin Wiki) - - - + Use OpenSSL (https) for JSON-RPC connections Použít OpenSSL (https) pro JSON-RPC spojení - + Server certificate file (default: server.cert) Soubor se serverovým certifikátem (výchozí: server.cert) - + Server private key (default: server.pem) Soubor se serverovým soukromým klíčem (výchozí: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akceptovatelné šifry (výchozí: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Tato nápověda - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Nedaří se mi získat zámek na datový adresář %s. Bitcoin pravděpodobně už jednou běží. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Nedaří se mi připojit na %s na tomhle počítači (operace bind vrátila chybu %d, %s) - + Connect through socks proxy - + Připojit se přes socks proxy - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Povolit DNS dotazy pro -addnode (přidání uzlu), -seednode a -connect (připojení) - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Načítám adresy... - - Error loading blkindex.dat - Chyba při načítání blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Chyba při načítání wallet.dat: peněženka je poškozená - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Chyba při načítání wallet.dat: peněženka vyžaduje novější verzi Bitcoinu + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Chyba při načítání wallet.dat: peněženka vyžaduje novější verzi CasinoCoinu - - Wallet needed to be rewritten: restart Bitcoin to complete - Soubor s peněženkou potřeboval přepsat: restartuj Bitcoin, aby se operace dokončila + + Wallet needed to be rewritten: restart CasinoCoin to complete + Soubor s peněženkou potřeboval přepsat: restartuj CasinoCoin, aby se operace dokončila - + Error loading wallet.dat Chyba při načítání wallet.dat - + Invalid -proxy address: '%s' - + Neplatná -proxy adresa: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + V -onlynet byla uvedena neznámá síť: '%s' - + Unknown -socks proxy version requested: %i - + V -socks byla požadována neznámá verze proxy: %i - + Cannot resolve -bind address: '%s' - + Nemohu přeložit -bind adresu: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Nemohu přeložit -externalip adresu: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Neplatná částka pro -paytxfee=<částka>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Chyba: Peněženka je zamčená, nemohu vytvořit transakci - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Chyba: Tahle transakce vyžaduje transakční poplatek nejméně %s kvůli velikosti zasílané částky, komplexnosti nebo použití nedávno přijatých mincí - - - - Error: Transaction creation failed - Chyba: Vytvoření transakce selhalo - - - - Sending... - Posílám... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Chyba Transakce byla odmítnuta. Tohle může nastat, pokud nějaké mince z tvé peněženky už jednou byly utraceny, například pokud používáš kopii souboru wallet.dat a mince byly utraceny v druhé kopii, ale nebyly označeny jako utracené v této. - - - + Invalid amount Neplatná částka - + Insufficient funds Nedostatek prostředků - + Loading block index... Načítám index bloků... - + Add a node to connect to and attempt to keep the connection open Přidat uzel, ke kterému se připojit a snažit se spojení udržet - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Nedaří se mi připojit na %s na tomhle počítači. CasinoCoin už pravděpodobně jednou běží. - - Find peers using internet relay chat (default: 0) - Hledat uzly přes IRC (výchozí: 0) - - - - Accept connections from outside (default: 1) - Přijímat spojení zvenčí (výchozí: 1) - - - - Find peers using DNS lookup (default: 1) - Hledat uzly přes DNS (výchozí: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Použít Universal Plug and Play k namapování naslouchacího portu (výchozí: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Použít Universal Plug and Play k namapování naslouchacího portu (výchozí: 0) - - - + Fee per KB to add to transactions you send - Poplatek za KB, který se přidá ke každé odeslané transakci + Poplatek za kB, který se přidá ke každé odeslané transakci - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Načítám peněženku... - + Cannot downgrade wallet Nemohu převést peněženku do staršího formátu - - Cannot initialize keypool - Nemohu inicializovat zásobník klíčů - - - + Cannot write default address Nemohu napsat výchozí adresu - + Rescanning... Přeskenovávám... - + Done loading Načítání dokončeno - + To use the %s option K použití volby %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, musíš nastavit rpcpassword v konfiguračním souboru: - %s -Je vhodné použít následující náhodné heslo: -rpcuser=bitcoinrpc -rpcpassword=%s -(není potřeba si ho pamatovat) -Pokud konfigurační soubor ještě neexistuje, vytvoř ho tak, aby ho mohl číst pouze vlastník. - - - - + Error Chyba - - An error occured while setting up the RPC port %i for listening: %s - Při nastavování naslouchacího RPC portu %i nastala chyba: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2511,10 +2934,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Pokud konfigurační soubor ještě neexistuje, vytvoř ho tak, aby ho mohl číst pouze vlastník. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Upozornění: Zkontroluj, že máš v počítači správně nastavený datum a čas. Pokud jsou nastaveny špatně, Bitcoin nebude fungovat správně. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts new file mode 100644 index 0000000..d38b5e4 --- /dev/null +++ b/src/qt/locale/bitcoin_cy.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + + + + + <b>CasinoCoin</b> version + Fersiwn <b>CasinoCoin</b> + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + Llyfr Cyfeiriadau + + + + Double-click to edit address or label + Clicio dwywaith i olygu cyfeiriad neu label + + + + Create a new address + Creu cyfeiriad newydd + + + + Copy the currently selected address to the system clipboard + Copio'r cyfeiriad sydd wedi'i ddewis i'r clipfwrdd system + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + &Dileu + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + Allforio Data Llyfr Cyfeiriad + + + + Comma separated file (*.csv) + + + + + Error exporting + Gwall allforio + + + + Could not write to file %1. + Ni ellir ysgrifennu i ffeil %1. + + + + AddressTableModel + + + Label + Label + + + + Address + Cyfeiriad + + + + (no label) + (heb label) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + Teipiwch gyfrinymadrodd + + + + New passphrase + Cyfrinymadrodd newydd + + + + Repeat new passphrase + Ailadroddwch gyfrinymadrodd newydd + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Dewiswch gyfrinymadrodd newydd ar gyfer y waled. <br/> Defnyddiwch cyfrinymadrodd o <b>10 neu fwy o lythyrennau hapgyrch</b>, neu <b> wyth neu fwy o eiriau. + + + + Encrypt wallet + Amgryptio'r waled + + + + This operation needs your wallet passphrase to unlock the wallet. + Mae angen i'r gweithred hon ddefnyddio'ch cyfrinymadrodd er mwyn datgloi'r waled. + + + + Unlock wallet + Datgloi'r waled + + + + This operation needs your wallet passphrase to decrypt the wallet. + Mae angen i'r gweithred hon ddefnyddio'ch cyfrinymadrodd er mwyn dadgryptio'r waled. + + + + Decrypt wallet + Dadgryptio'r waled + + + + Change passphrase + Newid cyfrinymadrodd + + + + Enter the old and new passphrase to the wallet. + Teipiwch yr hen cyfrinymadrodd a chyfrinymadrodd newydd i mewn i'r waled. + + + + Confirm wallet encryption + Cadarnau amgryptiad y waled + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + Waled wedi'i amgryptio + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + Amgryptiad waled wedi methu + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Methodd amgryptiad y waled oherwydd gwall mewnol. Ni amgryptwyd eich waled. + + + + + The supplied passphrases do not match. + Dydy'r cyfrinymadroddion a ddarparwyd ddim yn cyd-fynd â'u gilydd. + + + + Wallet unlock failed + Methodd ddatgloi'r waled + + + + + + The passphrase entered for the wallet decryption was incorrect. + + + + + Wallet decryption failed + Methodd dadgryptiad y waled + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + Cysoni â'r rhwydwaith... + + + + &Overview + &Trosolwg + + + + Show general overview of wallet + Dangos trosolwg cyffredinol y waled + + + + &Transactions + &Trafodion + + + + Browse transaction history + Pori hanes trafodion + + + + Edit the list of stored addresses and labels + Golygu'r rhestr o cyfeiriadau a labeli ar gadw + + + + Show the list of addresses for receiving payments + Dangos rhestr o gyfeiriadau ar gyfer derbyn taliadau + + + + E&xit + + + + + Quit application + Gadael rhaglen + + + + Show information about CasinoCoin + Dangos gwybodaeth am CasinoCoin + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + &Opsiynau + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + Newid y cyfrinymadrodd a ddefnyddiwyd ar gyfer amgryptio'r waled + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + &Ffeil + + + + &Settings + &Gosodiadau + + + + &Help + &Cymorth + + + + Tabs toolbar + Bar offer tabiau + + + + + [testnet] + [testnet] + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + Cyfamserol + + + + Catching up... + Dal i fyny + + + + Confirm transaction fee + + + + + Sent transaction + Trafodiad a anfonwyd + + + + Incoming transaction + Trafodiad sy'n cyrraedd + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Mae'r waled <b>wedi'i amgryptio</b> ac <b>heb ei gloi</b> ar hyn o bryd + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Mae'r waled <b>wedi'i amgryptio</b> ac <b>ar glo</b> ar hyn o bryd + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + Golygu'r cyfeiriad + + + + &Label + &Label + + + + The label associated with this address book entry + Mae'r label hon yn cysylltiedig gyda'r cofnod llyfr cyfeiriad hon + + + + &Address + &Cyfeiriad + + + + The address associated with this address book entry. This can only be modified for sending addresses. + Mae'r cyfeiriad hon yn cysylltiedig gyda'r cofnod llyfr cyfeiriad hon. Gall hyn gael ei olygu dim ond ar gyfer y pwrpas o anfon cyfeiriadau. + + + + New receiving address + Cyfeiriad derbyn newydd + + + + New sending address + Cyfeiriad anfon newydd + + + + Edit receiving address + Golygu'r cyfeiriad derbyn + + + + Edit sending address + Golygu'r cyfeiriad anfon + + + + The entered address "%1" is already in the address book. + Mae'r cyfeiriad "%1" sydd newydd gael ei geisio gennych yn y llyfr cyfeiriad yn barod. + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + Methodd ddatgloi'r waled. + + + + New key generation failed. + Methodd gynhyrchu allwedd newydd. + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + Opsiynau + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + Ffurflen + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + Gweddill: + + + + Unconfirmed: + Nas cadarnheir: + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + <b>Trafodion diweddar</b> + + + + Your current balance + Eich gweddill presennol + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + Cyfanswm o drafodion sydd heb eu cadarnhau a heb eu cyfri tuag at y gweddill presennol + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + Anfon arian + + + + Send to multiple recipients at once + Anfon at pobl lluosog ar yr un pryd + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + Gweddill: + + + + 123.456 BTC + 123.456 BTC + + + + Confirm the send action + Cadarnhau'r gweithrediad anfon + + + + S&end + + + + + <b>%1</b> to %2 (%3) + <b>%1</b> to %2 (%3) + + + + Confirm send coins + + + + + Are you sure you want to send %1? + Ydych chi'n siwr eich bod chi eisiau anfon %1? + + + + and + a + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + Ffurflen + + + + A&mount: + &Maint + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + &Label: + + + + Choose address from address book + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Gludo cyfeiriad o'r glipfwrdd + + + + Alt+P + Alt+P + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Gludo cyfeiriad o'r glipfwrdd + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + Agor tan %1 + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + Cyfeiriad + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + Agor tan %1 + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + Label + + + + Address + Cyfeiriad + + + + Amount + + + + + ID + + + + + Error exporting + Gwall allforio + + + + Could not write to file %1. + Ni ellir ysgrifennu i ffeil %1. + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 66166a7..d85f465 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -3,116 +3,160 @@ AboutDialog - - About Bitcoin - Om Bitcoin + + About CasinoCoin + Om CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> version + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> version - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - + +Dette program er ekperimentielt. + +Det er gjort tilgængeligt under MIT/X11-softwarelicensen. Se den tilhørende fil "COPYING" eller http://www.opensource.org/licenses/mit-license.php. + +Produktet indeholder software som er udviklet af OpenSSL Project til brug i OpenSSL Toolkit (http://www.openssl.org/), kryptografisk software skrevet af Eric Young (eay@cryptsoft.com) og UPnP-software skrevet af Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers + CasinoCoin-udviklerne AddressBookPage - + Address Book Adressebog - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Dette er dine Bitcoinadresser til at modtage betalinger med. Du kan give en forskellig adresse til hver afsender, så du kan holde styr på hvem der betaler dig. - - - + Double-click to edit address or label Dobbeltklik for at redigere adresse eller mærkat - + Create a new address Opret en ny adresse - + Copy the currently selected address to the system clipboard Kopier den valgte adresse til systemets udklipsholder - + &New Address - + Ny adresse - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Dette er dine CasinoCoin-adresser til at modtage betalinger med. Du kan give en forskellig adresse til hver afsender, så du kan holde styr på, hvem der betaler dig. + + + &Copy Address - + Kopier adresse - + Show &QR Code - + Vis QR-kode - - Sign a message to prove you own this address - + + Sign a message to prove you own a CasinoCoin address + Underskriv en besked for at bevise, at en CasinoCoin-adresse tilhører dig - - &Sign Message - + + Sign &Message + Underskriv besked - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Slet den valgte adresse fra listen. Kun adresser brugt til afsendelse kan slettes. + + Delete the currently selected address from the list + Slet den markerede adresse fra listen - + + Export the data in the current tab to a file + Eksportér den aktuelle visning til en fil + + + + &Export + Eksporter + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Efterprøv en besked for at sikre, at den er underskrevet med den angivne CasinoCoin-adresse + + + + &Verify Message + Efterprøv besked + + + &Delete - &Slet + Slet - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Disse er dine CasinoCoin-adresser for at sende betalinger. Tjek altid beløb og modtageradresse, inden du sender casinocoins. + + + Copy &Label - + Kopier mærkat - + &Edit - + Rediger - + + Send &Coins + Send casinocoins + + + Export Address Book Data - Eksporter Adressekartoteketsdata + Eksporter adressebogsdata - + Comma separated file (*.csv) - Kommasepareret fil (*. csv) + Kommasepareret fil (*.csv) - + Error exporting Fejl under eksport - + Could not write to file %1. Kunne ikke skrive til filen %1. @@ -120,450 +164,478 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label - Etiket + Mærkat - + Address Adresse - + (no label) - (ingen etiket) + (ingen mærkat) AskPassphraseDialog - + Passphrase Dialog - + Adgangskodedialog - + Enter passphrase Indtast adgangskode - + New passphrase Ny adgangskode - + Repeat new passphrase Gentag ny adgangskode - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - Indtast den nye adgangskode til tegnebogen.<br/>Brug venligst en adgangskode på <b>10 eller flere tilfældige tegn</b>, eller <b>otte eller flere ord</b>. + Indtast den nye adgangskode til tegnebogen.<br/>Brug venligst en adgangskode på <b>10 eller flere tilfældige tegn</b> eller <b>otte eller flere ord</b>. - + Encrypt wallet Krypter tegnebog - + This operation needs your wallet passphrase to unlock the wallet. - Denne funktion har brug for din tegnebogs kodeord for at låse tegnebogen op. + Denne funktion har brug for din tegnebogs adgangskode for at låse tegnebogen op. - + Unlock wallet Lås tegnebog op - + This operation needs your wallet passphrase to decrypt the wallet. - Denne funktion har brug for din tegnebogs kodeord for at dekryptere tegnebogen. + Denne funktion har brug for din tegnebogs adgangskode for at dekryptere tegnebogen. - + Decrypt wallet - Dekryptér tegnebog + Dekrypter tegnebog - + Change passphrase Skift adgangskode - + Enter the old and new passphrase to the wallet. - Indtast den gamle og nye adgangskode til tegnebogen. + Indtast den gamle og den nye adgangskode til tegnebogen. - + Confirm wallet encryption Bekræft tegnebogskryptering - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ADVARSEL: Hvis du krypterer din tegnebog og mister dit kodeord vil du <b>miste alle dine BITCOINS</b>! -Er du sikker på at du ønsker at kryptere din tegnebog? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Advarsel: Hvis du krypterer din tegnebog og mister din adgangskode, vil du <b>MISTE ALLE DINE CASINOCOINS</b>! - - + + Are you sure you wish to encrypt your wallet? + Er du sikker på, at du ønsker at kryptere din tegnebog? + + + + 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. + 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 ubrugelig i det øjeblik, du starter med at anvende den nye, krypterede tegnebog. + + + + + Warning: The Caps Lock key is on! + Advarsel: Caps Lock-tasten er aktiveret! + + + + Wallet encrypted Tegnebog krypteret - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin vil nu lukke for at gennemføre krypteringsprocessen. Husk på, at kryptering af din tegnebog vil ikke beskytte dine casinocoins fuldt ud mod at blive stjålet af malware på din computer. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed Tegnebogskryptering mislykkedes - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Tegnebogskryptering mislykkedes på grund af en intern fejl. Din tegnebog blev ikke krypteret. - - + + The supplied passphrases do not match. - De angivne kodeord stemmer ikke overens. + De angivne adgangskoder stemmer ikke overens. - + Wallet unlock failed Tegnebogsoplåsning mislykkedes - - - + + + The passphrase entered for the wallet decryption was incorrect. - Det angivne kodeord for tegnebogsdekrypteringen er forkert. + Den angivne adgangskode for tegnebogsdekrypteringen er forkert. - + Wallet decryption failed Tegnebogsdekryptering mislykkedes - - Wallet passphrase was succesfully changed. - Tegnebogskodeord blev ændret. + + Wallet passphrase was successfully changed. + Tegnebogens adgangskode blev ændret. BitcoinGUI - - Bitcoin Wallet - Bitcoin Tegnebog - - - + Sign &message... - + Underskriv besked... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... - Synkroniserer med netværk ... + Synkroniserer med netværk... - + &Overview - &Oversigt + Oversigt - + Show general overview of wallet Vis generel oversigt over tegnebog - + &Transactions - &Transaktioner + Transaktioner - + Browse transaction history Gennemse transaktionshistorik - - &Address Book - &Adressebog - - - + Edit the list of stored addresses and labels - Rediger listen over gemte adresser og etiketter + Rediger listen over gemte adresser og mærkater - - &Receive coins - &Modtag coins - - - + Show the list of addresses for receiving payments Vis listen over adresser for at modtage betalinger - - &Send coins - &Send coins - - - - Prove you control an address - - - - + E&xit - &Luk + Luk - + Quit application Afslut program - - &About %1 - &Om %1 + + Show information about CasinoCoin + Vis informationer om CasinoCoin - - Show information about Bitcoin - Vis oplysninger om Bitcoin - - - + About &Qt - + Om Qt - + Show information about Qt - + Vis informationer om Qt - + &Options... - &Indstillinger ... + Indstillinger... - + &Encrypt Wallet... - + Krypter tegnebog... - + &Backup Wallet... - + Sikkerhedskopier tegnebog... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + Skift adgangskode... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Importerer blokke fra disken... - - &Export... - &Eksporter... + + Reindexing blocks on disk... + Genindekserer blokke på disken... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Send casinocoins til en CasinoCoin-adresse - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Rediger konfigurationsindstillinger af CasinoCoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - Kryptér eller dekryptér tegnebog - - - + Backup wallet to another location - + Lav sikkerhedskopi af tegnebogen til et andet sted - + Change the passphrase used for wallet encryption - Skift kodeord anvendt til tegnebogskryptering + Skift adgangskode anvendt til tegnebogskryptering - + &Debug window - + Fejlsøgningsvindue - + Open debugging and diagnostic console - + Åbn fejlsøgnings- og diagnosticeringskonsollen - + &Verify message... - + Efterprøv besked... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Tegnebog + + + + &Send + Send + + + + &Receive + Modtag + + + + &Addresses + Adresser + + + + &About CasinoCoin + Om CasinoCoin + + + + &Show / Hide + Vis/skjul + + + + Show or hide the main Window + Vis eller skjul hovedvinduet + + + + Encrypt the private keys that belong to your wallet + Krypter de private nøgler, der hører til din tegnebog + + + + Sign messages with your CasinoCoin addresses to prove you own them + Underskriv beskeder med dine CasinoCoin-adresser for at bevise, at de tilhører dig + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Efterprøv beskeder for at sikre, at de er underskrevet med de(n) angivne CasinoCoin-adresse(r) + + + &File - &Fil + Fil - + &Settings - &Indstillinger + Indstillinger - + &Help - &Hjælp + Hjælp - + Tabs toolbar Faneværktøjslinje - - Actions toolbar - Handlingsværktøjslinje - - - - + + [testnet] - [testnet] + [testnetværk] - - - Bitcoin client - + + CasinoCoin client + CasinoCoin-klient - - %n active connection(s) to Bitcoin network - %n aktiv(e) forbindelse(r) til Bitcoinnetværket%n aktiv(e) forbindelse(r) til Bitcoinnetværket + + %n active connection(s) to CasinoCoin network + %n aktiv(e) forbindelse(r) til CasinoCoin-netværket%n aktiv(e) forbindelse(r) til CasinoCoin-netværket - - Downloaded %1 blocks of transaction history. - Downloadet %1 blokke af transaktionshistorie. - - - - %n second(s) ago - %n sekund(er) siden%n sekund(er) siden - - - - %n minute(s) ago - %n minut(ter) siden%n minut(ter) siden - - - - %n hour(s) ago - %n time(r) siden%n time(r) siden - - - - %n day(s) ago - %n dag(e) siden%n dag(e) siden + + No block source available... + Ingen blokkilde tilgængelig... - + + Processed %1 of %2 (estimated) blocks of transaction history. + %1 ud af %2 (estimeret) blokke af transaktionshistorikken er blevet behandlet. + + + + Processed %1 blocks of transaction history. + %1 blokke af transaktionshistorikken er blevet behandlet. + + + + %n hour(s) + %n time(r)%n time(r) + + + + %n day(s) + %n dag(e)%n dag(e) + + + + %n week(s) + %n uge(r)%n uge(r) + + + + %1 behind + %1 bagefter + + + + Last received block was generated %1 ago. + Senest modtagne blok blev genereret for %1 siden. + + + + Transactions after this will not yet be visible. + Transaktioner herefter vil endnu ikke være synlige. + + + + Error + Fejl + + + + Warning + Advarsel + + + + Information + Information + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Transaktionen overskrider størrelsesgrænsen. Du kan stadig sende den for et gebyr på %1, hvilket går til de knuder, der behandler din transaktion og hjælper med at understøtte netværket. Vil du betale gebyret? + + + Up to date Opdateret - + Catching up... Indhenter... - - Last received block was generated %1. - Sidst modtagne blok blev genereret %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Denne transaktion er over størrelsesbegrænsningen. Du kan stadig sende den for et gebyr på %1 som går til de noder der behandler din transaktion, og som hjælper med at støtte netværket. Ønsker du at betale gebyret? - - - + Confirm transaction fee - + Bekræft transaktionsgebyr - + Sent transaction Afsendt transaktion - + Incoming transaction Indgående transaktion - + Date: %1 Amount: %2 Type: %3 @@ -576,993 +648,1199 @@ Adresse: %4 - + + + URI handling + URI-håndtering + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI kan ikke fortolkes! Dette kan skyldes en ugyldig CasinoCoin-adresse eller misdannede URI-parametre. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Tegnebog er <b>krypteret</b> og i øjeblikket <b>ulåst</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Tegnebog er <b>krypteret</b> og i øjeblikket <b>låst</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Der opstod en fatal fejl. CasinoCoin kan ikke længere fortsætte sikkert og vil afslutte. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Visning - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Vælg den standard underopdelingsenhed som skal vises i brugergrænsefladen, og når du sender coins - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Netværksadvarsel EditAddressDialog - + Edit Address - Rediger Adresse + Rediger adresse - + &Label - &Etiket + Mærkat - + The label associated with this address book entry - Etiketten forbundet med denne post i adressekartoteket + Mærkaten forbundet med denne post i adressebogen - + &Address - &Adresse + Adresse - + The address associated with this address book entry. This can only be modified for sending addresses. - Adressen tilknyttet til denne post i adressekartoteket. Dette kan kun ændres for afsendelsesadresser. + Adressen tilknyttet til denne post i adressebogen. Dette kan kun ændres for afsendelsesadresser. - + New receiving address Ny modtagelsesadresse - + New sending address Ny afsendelsesadresse - + Edit receiving address Rediger modtagelsesadresse - + Edit sending address Rediger afsendelsesadresse - + The entered address "%1" is already in the address book. Den indtastede adresse "%1" er allerede i adressebogen. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Den indtastede adresse "%1" er ikke en gyldig CasinoCoin-adresse. - + Could not unlock wallet. Kunne ikke låse tegnebog op. - + New key generation failed. Ny nøglegenerering mislykkedes. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + version - + Usage: Anvendelse: - - options - + + command-line options + kommandolinjetilvalg - + UI options - + Brugergrænsefladeindstillinger - + Set language, for example "de_DE" (default: system locale) - + Angiv sprog, f.eks "de_DE" (standard: systemlokalitet) - + Start minimized - Start minimeret - + Start minimeret - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - Betal transaktions&gebyr - - - - Main - Generelt - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Vælg adresse fra adressebog - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Indsæt adresse fra udklipsholderen - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Indtast en Bitcoinadresse (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - Konfigurer port vha. &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Åbn Bitcoinklient-porten på routeren automatisk. Dette virker kun når din router understøtter UPnP og UPnP er aktiveret. - - - - &Connect through SOCKS4 proxy: - &Forbind gennem SOCKS4 proxy: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Opret forbindelse til Bitconnetværket via en SOCKS4 proxy (f.eks. ved tilslutning gennem Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - IP-adressen på proxyen (f.eks. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Porten på proxyen (f.eks. 1234) + Vis opstartsbillede ved start (standard: 1) OptionsDialog - + Options Indstillinger + + + &Main + Generelt + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Valgfrit transaktionsgebyr pr. kB, der hjælper dine transaktioner med at blive behandlet hurtigt. De fleste transaktioner er på 1 kB. + + + + Pay transaction &fee + Betal transaktionsgebyr + + + + Automatically start CasinoCoin after logging in to the system. + Start CasinoCoin automatisk, når der logges ind på systemet + + + + &Start CasinoCoin on system login + Start CasinoCoin, når systemet startes + + + + Reset all client options to default. + Nulstil alle klientindstillinger til deres standard. + + + + &Reset Options + Nulstil indstillinger + + + + &Network + Netværk + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Åbn CasinoCoin-klientens port på routeren automatisk. Dette virker kun, når din router understøtter UPnP og UPnP er aktiveret. + + + + Map port using &UPnP + Konfigurer port vha. UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Opret forbindelse til CasinoCoin-netværket via en SOCKS-proxy (f.eks. ved tilslutning gennem Tor) + + + + &Connect through SOCKS proxy: + Forbind gennem SOCKS-proxy: + + + + Proxy &IP: + Proxy-IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + IP-adressen på proxyen (f.eks. 127.0.0.1) + + + + &Port: + Port: + + + + Port of the proxy (e.g. 9050) + Porten på proxyen (f.eks. 9050) + + + + SOCKS &Version: + SOCKS-version + + + + SOCKS version of the proxy (e.g. 5) + SOCKS-version af proxyen (f.eks. 5) + + + + &Window + Vindue + + + + Show only a tray icon after minimizing the window. + Vis kun et statusikon efter minimering af vinduet. + + + + &Minimize to the tray instead of the taskbar + Minimer til statusfeltet i stedet for proceslinjen + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimer i stedet for at afslutte programmet, når vinduet lukkes. Når denne indstilling er valgt, vil programmet kun blive lukket, når du har valgt Afslut i menuen. + + + + M&inimize on close + Minimer ved lukning + + + + &Display + Visning + + + + User Interface &language: + Brugergrænsefladesprog: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Brugergrænsefladesproget kan angives her. Denne indstilling træder først i kraft, når CasinoCoin genstartes. + + + + &Unit to show amounts in: + Enhed at vise beløb i: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Vælg den standard underopdelingsenhed, som skal vises i brugergrænsefladen og ved afsendelse af casinocoins. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Afgør hvorvidt CasinoCoin-adresser skal vises i transaktionslisten eller ej. + + + + &Display addresses in transaction list + Vis adresser i transaktionsliste + + + + &OK + OK + + + + &Cancel + Annuller + + + + &Apply + Anvend + + + + default + standard + + + + Confirm options reset + Bekræft nulstilling af indstillinger + + + + Some settings may require a client restart to take effect. + Nogle indstillinger kan kræve, at klienten genstartes, før de træder i kraft. + + + + Do you want to proceed? + Ønsker du at fortsætte? + + + + + Warning + Advarsel + + + + + This setting will take effect after restarting CasinoCoin. + Denne indstilling træder i kraft, efter CasinoCoin genstartes. + + + + The supplied proxy address is invalid. + Ugyldig proxy-adresse + OverviewPage - + Form Formular - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Den viste information kan være forældet. Din tegnebog synkroniserer automatisk med CasinoCoin-netværket, når en forbindelse etableres, men denne proces er ikke gennemført endnu. - + Balance: Saldo: - - Number of transactions: - Antal transaktioner: - - - + Unconfirmed: Ubekræftede: - + Wallet - + Tegnebog - + + Immature: + Umodne: + + + + Mined balance that has not yet matured + Udvunden saldo, som endnu ikke er modnet + + + <b>Recent transactions</b> <b>Nyeste transaktioner</b> - + Your current balance Din nuværende saldo - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Summen af ​​transaktioner, der endnu ikke er bekræftet, og endnu ikke er inkluderet i den nuværende saldo + Summen af transaktioner, der endnu ikke er bekræftet og endnu ikke er inkluderet i den nuværende saldo - - Total number of transactions in wallet - Samlede antal transaktioner i tegnebogen - - - - + + out of sync - + ikke synkroniseret + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Kan ikke starte casinocoin: click-to-pay-håndtering QRCodeDialog - + QR Code Dialog - + QR-kode-dialog - - QR Code - - - - + Request Payment - + Anmod om betaling - + Amount: - + Beløb: - - BTC - - - - + Label: - + Mærkat: - + Message: Besked: - + &Save As... - + Gem som... - + Error encoding URI into QR Code. - + Fejl ved kodning fra URI til QR-kode - + + The entered amount is invalid, please check. + Det indtastede beløb er ugyldig, tjek venligst. + + + Resulting URI too long, try to reduce the text for label / message. - + Resulterende URI var for lang; prøv at forkorte teksten til mærkaten/beskeden. - + Save QR Code - + Gem QR-kode - + PNG Images (*.png) - + PNG-billeder (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Klientnavn - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + Klientversion - + &Information - + Information - - Client - + + Using OpenSSL version + Anvendt OpenSSL-version - + Startup time - + Opstartstid - + Network - + Netværk - + Number of connections - + Antal forbindelser - + On testnet - + Tilsluttet testnetværk - + Block chain - + Blokkæde - + Current number of blocks - + Nuværende antal blokke - + Estimated total blocks - + Estimeret antal blokke - + Last block time - + Tidsstempel for seneste blok - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + Åbn - + + Command-line options + Kommandolinjetilvalg + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Vis CasinoCoin-Qt-hjælpebeskeden for at få en liste over de tilgængelige CasinoCoin-kommandolinjeindstillinger. + + + + &Show + Vis + + + &Console - + Konsol - + Build date - + Byggedato - + + CasinoCoin - Debug window + CasinoCoin - Fejlsøgningsvindue + + + + CasinoCoin Core + CasinoCoin Core + + + + Debug log file + Fejlsøgningslogfil + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Åbn CasinoCoin-fejlsøgningslogfilen fra det nuværende datakatalog. Dette kan tage nogle få sekunder for en store logfiler. + + + Clear console - + Ryd konsol - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Velkommen til CasinoCoin RPC-konsollen - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Brug op og ned-piletasterne til at navigere historikken og <b>Ctrl-L</b> til at rydde skærmen. - + Type <b>help</b> for an overview of available commands. - + Tast <b>help</b> for en oversigt over de tilgængelige kommandoer. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Send Coins + Send casinocoins - + Send to multiple recipients at once - Send til flere modtagere på én gang + Send til flere modtagere på en gang - - &Add Recipient - + + Add &Recipient + Tilføj modtager - + Remove all transaction fields - + Fjern alle transaktionsfelter - + Clear &All - + Ryd alle - + Balance: Saldo: - + 123.456 BTC - 123.456 BTC + 123,456 BTC - + Confirm the send action Bekræft afsendelsen - - &Send - &Afsend + + S&end + Afsend - + <b>%1</b> to %2 (%3) <b>%1</b> til %2 (%3) - + Confirm send coins - Bekræft afsendelse af coins + Bekræft afsendelse af casinocoins - + Are you sure you want to send %1? - Er du sikker på at du vil sende %1? + Er du sikker på, at du vil sende %1? - + and og - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Modtagerens adresse er ikke gyldig. Tjek venligst adressen igen. - + The amount to pay must be larger than 0. Beløbet til betaling skal være større end 0. - + The amount exceeds your balance. - + Beløbet overstiger din saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + Totalen overstiger din saldo, når %1 transaktionsgebyr er inkluderet. - + Duplicate address found, can only send to each address once per send operation. - + Duplikeret adresse fundet. Du kan kun sende til hver adresse en gang pr. afsendelse. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Fejl: Oprettelse af transaktionen mislykkedes! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Fejl: Transaktionen blev afvist. Dette kan ske, hvis nogle af dine casinocoins i din tegnebog allerede er brugt, som hvis du brugte en kopi af wallet.dat og dine casinocoins er blevet brugt i kopien, men ikke er markeret som brugt her. SendCoinsEntry - + Form Formular - + A&mount: - B&eløb: + Beløb: - + Pay &To: - Betal &Til: + Betal til: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin-adressen som betalingen skal sendes til (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book - Indtast en etiket for denne adresse for at føje den til din adressebog + Indtast en mærkat for denne adresse for at føje den til din adressebog - + &Label: - &Etiket: + Mærkat: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresse som betalingen skal sendes til (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Vælg adresse fra adressebog - + Alt+A Alt+A - + Paste address from clipboard Indsæt adresse fra udklipsholderen - + Alt+P Alt+P - + Remove this recipient Fjern denne modtager - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Indtast en Bitcoinadresse (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Indtast en CasinoCoin-adresse (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Underskrifter - Underskriv/efterprøv en besked + + + + &Sign Message + Underskriv besked + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Du kan underskrive beskeder med dine CasinoCoin-adresser for at bevise, at de tilhører dig. Pas på ikke at underskrive noget vagt, da phisingangreb kan narre dig til at overdrage din identitet. Underskriv kun fuldt detaljerede udsagn, du er enig i. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin-adressen som beskeden skal underskrives med (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Vælg adresse fra adressebog + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Indsæt adresse fra udklipsholderen + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Indtast beskeden, du ønsker at underskrive + + + + Signature + Underskrift + + + + Copy the current signature to the system clipboard + Kopier den nuværende underskrift til systemets udklipsholder + + + + Sign the message to prove you own this CasinoCoin address + Underskriv denne besked for at bevise, at CasinoCoin-adressen tilhører dig + + + + Sign &Message + Underskriv besked + + + + Reset all sign message fields + Nulstil alle underskriv besked-indtastningsfelter + + + + + Clear &All + Ryd alle + + + + &Verify Message + Efterprøv besked + + + + Enter the signing 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. + Indtast den underskrevne adresse, beskeden (inkluder linjeskift, mellemrum mv. nøjagtigt, som de fremgår) og underskriften for at efterprøve beskeden. Vær forsigtig med ikke at lægge mere i underskriften end besked selv, så du undgår at blive narret af et man-in-the-middle-angreb. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin-adressen som beskeden er underskrevet med (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Efterprøv beskeden for at sikre, at den er underskrevet med den angivne CasinoCoin-adresse + + + + Verify &Message + Efterprøv besked + + + + Reset all verify message fields + Nulstil alle efterprøv besked-indtastningsfelter + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Indtast en CasinoCoin-adresse (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Klik "Underskriv besked" for at generere underskriften + + + + Enter CasinoCoin signature + Indtast CasinoCoin-underskriften + + + + + The entered address is invalid. + Den indtastede adresse er ugyldig. + + + + + + + Please check the address and try again. + Tjek venligst adressen, og forsøg igen. + + + + + The entered address does not refer to a key. + Den indtastede adresse henviser ikke til en nøgle. + + + + Wallet unlock was cancelled. + Tegnebogsoplåsning annulleret. + + + + Private key for the entered address is not available. + Den private nøgle for den indtastede adresse er ikke tilgængelig. + + + + Message signing failed. + Underskrivning af besked mislykkedes. + + + + Message signed. + Besked underskrevet. + + + + The signature could not be decoded. + Underskriften kunne ikke afkodes. + + + + + Please check the signature and try again. + Tjek venligst underskriften, og forsøg igen. + + + + The signature did not match the message digest. + Underskriften matcher ikke beskedens indhold. + + + + Message verification failed. + Efterprøvelse af besked mislykkedes. + + + + Message verified. + Besked efterprøvet. + + + + SplashScreen + + + The CasinoCoin developers + CasinoCoin-udviklerne + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Åben for %1 blokke - - - + Open until %1 Åben indtil %1 - - %1/offline? - %1/offline? + + %1/offline + %1/offline - + %1/unconfirmed %1/ubekræftet - + %1 confirmations %1 bekræftelser - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , transmitteret igennem %n knude(r), transmitteret igennem %n knude(r) - + + Date + Dato + + + + Source + Kilde + + + + Generated + Genereret + + + + + From + Fra + + + + + + To + Til + + + + + own address + egen adresse + + + + label + mærkat + + + + + + + + Credit + Kredit + + + + matures in %n more block(s) + modner efter yderligere %n blok(ke)modner efter yderligere %n blok(ke) + + + + not accepted + ikke accepteret + + + + + + + Debit + Debet + + + + Transaction fee + Transaktionsgebyr + + + + Net amount + Nettobeløb + + + + Message + Besked + + + + Comment + Kommentar + + + + Transaction ID + Transaktionens ID + + + + Generated coins must mature 120 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. + Genererede casinocoins skal vente 120 blokke, før de kan blive brugt. Da du genererede denne blok, blev den transmitteret til netværket for at blive føjet til blokkæden. Hvis det mislykkes at komme ind i kæden, vil den skifte til "ikke godkendt" og ikke blive kunne bruges. Dette kan lejlighedsvis ske, hvis en anden knude genererer en blok inden for få sekunder af din. + + + + Debug information + Fejlsøgningsinformation + + + + Transaction + Transaktion + + + + Inputs + Input + + + + Amount + Beløb + + + + true + sand + + + + false + falsk + + + , has not been successfully broadcast yet , er ikke blevet transmitteret endnu - - - , broadcast through %1 node - , transmitteret via %1 node + + + Open for %n more block(s) + Åben %n blok yderligereÅben %n blokke yderligere - - , broadcast through %1 nodes - , transmitteret via %1 noder - - - - <b>Date:</b> - <b>Dato:</b> - - - - <b>Source:</b> Generated<br> - <b>Kilde:</b> Genereret<br> - - - - - <b>From:</b> - <b>Fra:</b> - - - + unknown ukendt - - - - - <b>To:</b> - <b>Til:</b> - - - - (yours, label: - (din, etiket: - - - - (yours) - (din) - - - - - - - <b>Credit:</b> - <b>Kredit:</b> - - - - (%1 matures in %2 more blocks) - (%1 modnes i %2 blokke mere) - - - - (not accepted) - (ikke accepteret) - - - - - - <b>Debit:</b> - <b>Debet:</b> - - - - <b>Transaction fee:</b> - <b>Transaktionsgebyr:</b> - - - - <b>Net amount:</b> - <b>Nettobeløb:</b> - - - - Message: - Besked: - - - - Comment: - Kommentar: - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Genererede coins skal vente 120 blokke, før de kan blive brugt. Da du genererede denne blok blev det transmitteret til netværket, for at blive føjet til blokkæden. Hvis det mislykkes at komme ind i kæden, vil den skifte til "ikke godkendt", og ikke blive kunne bruges. Dette kan lejlighedsvis ske, hvis en anden node genererer en blok inden for få sekunder af din. - TransactionDescDialog - + Transaction details Transaktionsdetaljer - + This pane shows a detailed description of the transaction Denne rude viser en detaljeret beskrivelse af transaktionen @@ -1570,117 +1848,117 @@ Adresse: %4 TransactionTableModel - + Date Dato - + Type Type - + Address Adresse - + Amount Beløb - - Open for %n block(s) - Åben for %n blok(ke)Åben for %n blok(ke) + + Open for %n more block(s) + Åben %n blok(ke) yderligereÅben %n blok(ke) yderligere - + Open until %1 Åben indtil %1 - + Offline (%1 confirmations) Offline (%1 bekræftelser) - + Unconfirmed (%1 of %2 confirmations) Ubekræftet (%1 af %2 bekræftelser) - + Confirmed (%1 confirmations) Bekræftet (%1 bekræftelser) - - Mined balance will be available in %n more blocks - Minerede balance vil være tilgængelig om %n blok(ke)Minerede balance vil være tilgængelig om %n blok(ke) + + Mined balance will be available when it matures in %n more block(s) + Udvunden saldo, som vil være tilgængelig, når den modner efter yderligere %n blok(ke)Udvunden saldo, som vil være tilgængelig, når den modner efter yderligere %n blok(ke) - + This block was not received by any other nodes and will probably not be accepted! - Denne blok blev ikke modtaget af nogen andre noder, og vil formentlig ikke blive accepteret! + Denne blok blev ikke modtaget af nogen andre knuder og vil formentlig ikke blive accepteret! - + Generated but not accepted Genereret, men ikke accepteret - + Received with Modtaget med - + Received from - + Modtaget fra - + Sent to Sendt til - + Payment to yourself Betaling til dig selv - + Mined - Minerede + Udvundne - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. - Transactionsstatus. Hold musen over dette felt for at vise antallet af bekræftelser. + Transaktionsstatus. Hold musen over dette felt for at vise antallet af bekræftelser. - + Date and time that the transaction was received. - Dato og tid for at transaktionen blev modtaget. + Dato og klokkeslæt for modtagelse af transaktionen. - + Type of transaction. - Type af transaktion. + Transaktionstype. - + Destination address of transaction. Destinationsadresse for transaktion. - + Amount removed from or added to balance. Beløb fjernet eller tilføjet balance. @@ -1688,845 +1966,973 @@ Adresse: %4 TransactionView - - + + All Alle - + Today I dag - + This week Denne uge - + This month Denne måned - + Last month Sidste måned - + This year Dette år - + Range... Interval... - + Received with Modtaget med - + Sent to Sendt til - + To yourself Til dig selv - + Mined - Minerede + Udvundne - + Other Andet - + Enter address or label to search - Indtast adresse eller etiket for at søge + Indtast adresse eller mærkat for at søge - + Min amount - Min. beløb + Minimumsbeløb - + Copy address Kopier adresse - + Copy label - Kopier etiket + Kopier mærkat - + Copy amount - + Kopier beløb - + + Copy transaction ID + Kopier transaktionens ID + + + Edit label - Rediger etiket + Rediger mærkat - + Show transaction details - + Vis transaktionsdetaljer - + Export Transaction Data - Eksportér Transaktionsdata + Eksporter transaktionsdata - + Comma separated file (*.csv) Kommasepareret fil (*.csv) - + Confirmed Bekræftet - + Date Dato - + Type Type - + Label - Etiket + Mærkat - + Address Adresse - + Amount Beløb - + ID ID - + Error exporting Fejl under eksport - + Could not write to file %1. Kunne ikke skrive til filen %1. - + Range: Interval: - + to til - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopier den valgte adresse til systemets udklipsholder - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Sender... + + Send Coins + Send casinocoins - WindowOptionsPage + WalletView - - Window - + + &Export + Eksporter - - &Minimize to the tray instead of the taskbar - &Minimer til systembakken i stedet for proceslinjen + + Export the data in the current tab to a file + Eksportér den aktuelle visning til en fil - - Show only a tray icon after minimizing the window - Vis kun et systembakkeikon efter minimering af vinduet + + Backup Wallet + Sikkerhedskopier tegnebog - - M&inimize on close - + + Wallet Data (*.dat) + Tegnebogsdata (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimer i stedet for at afslutte programmet når vinduet lukkes. Når denne indstilling er valgt vil programmet kun blive lukket når du har valgt Afslut i menuen. + + Backup Failed + Foretagelse af sikkerhedskopi fejlede + + + + There was an error trying to save the wallet data to the new location. + Der opstod en fejl i forbindelse med at gemme tegnebogsdata til det nye sted + + + + Backup Successful + Sikkerhedskopieret problemfri + + + + The wallet data was successfully saved to the new location. + Tegnebogsdata blev problemfrit gemt til det nye sted. bitcoin-core - - Bitcoin version - Bitcoinversion + + CasinoCoin version + CasinoCoin-version - + Usage: Anvendelse: - - Send command to -server or bitcoind - Send kommando til -server eller bitcoind - + + Send command to -server or casinocoind + Send kommando til -server eller casinocoind - + List commands - Liste over kommandoer - + Liste over kommandoer - + Get help for a command - Få hjælp til en kommando - + Få hjælp til en kommando - + Options: - Indstillinger: - + Indstillinger: - - Specify configuration file (default: bitcoin.conf) - Angiv konfigurationsfil (standard: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Angiv konfigurationsfil (standard: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Angiv pid-fil (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + Angiv pid-fil (default: casinocoind.pid) - - Generate coins - Generér coins - - - - - Don't generate coins - Generér ikke coins - - - - + Specify data directory - Angiv databibliotek - + Angiv datakatalog - + Set database cache size in megabytes (default: 25) - + Angiv databasecachestørrelse i megabytes (standard: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Lyt til forbindelser på <port> (standard: 47950 eller testnetværk: 17950) - - Specify connection timeout (in milliseconds) - Angiv tilslutningstimeout (i millisekunder) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + Oprethold højest <n> forbindelser til andre i netværket (standard: 125) - - Connect only to the specified node - Tilslut kun til den angivne node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Forbind til en knude for at modtage adresse, og afbryd - + Specify your own public address - + Angiv din egen offentlige adresse - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Grænse for afbrydelse til dårlige forbindelser (standard: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + Antal sekunder dårlige forbindelser skal vente før reetablering (standard: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Der opstod en fejl ved angivelse af RPC-porten %u til at lytte på IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Lyt til JSON-RPC-forbindelser på <port> (standard: 47970 eller testnetværk: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - Accepter kommandolinje- og JSON-RPC-kommandoer - + Accepter kommandolinje- og JSON-RPC-kommandoer - + Run in the background as a daemon and accept commands - Kør i baggrunden som en service, og acceptér kommandoer - + Kør i baggrunden som en service, og accepter kommandoer - + Use the test network - Brug test-netværket + Brug testnetværket + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accepter forbindelser udefra (standard: 1 hvis hverken -proxy eller -connect) + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, du skal angive en RPC-adgangskode i konfigurationsfilen: +%s +Det anbefales, at du bruger nedenstående, tilfældige adgangskode: +rpcuser=casinocoinrpc +rpcpassword=%s +(du behøver ikke huske denne adgangskode) +Brugernavnet og adgangskode MÅ IKKE være det samme. +Hvis filen ikke eksisterer, opret den og giv ingen andre end ejeren læserettighed. +Det anbefales også at angive alertnotify, så du påmindes om problemer; +f.eks.: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - - Output extra debugging information - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Der opstod en fejl ved angivelse af RPC-porten %u til at lytte på IPv6, falder tilbage til IPv4: %s - + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Tildel til den givne adresse og lyt altid på den. Brug [vært]:port-notation for IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Kan ikke opnå lås på datakatalog %s. CasinoCoin er sandsynligvis allerede startet. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Fejl: Transaktionen blev afvist. Dette kan ske, hvis nogle af dine casinocoins i din tegnebog allerede er brugt, som hvis du brugte en kopi af wallet.dat og dine casinocoins er blevet brugt i kopien, men ikke er markeret som brugt her. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Fejl: Denne transaktion kræver et transaktionsgebyr på minimum %s pga. dens størrelse, kompleksitet eller anvendelse af nyligt modtagne casinocoins! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Udfør kommando, når en relevant advarsel modtages (%s i kommandoen erstattes med beskeden) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Udfør kommando, når en transaktion i tegnebogen ændres (%s i kommandoen erstattes med TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Angiv maksimumstørrelse for høj prioritet/lavt gebyr-transaktioner i bytes (standard: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Dette er en foreløbig testudgivelse - brug på eget ansvar - brug ikke til udvinding eller handelsprogrammer + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Advarsel: -paytxfee er sat meget højt! Dette er det gebyr du vil betale, hvis du sender en transaktion. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Advarsel: Viste transaktioner kan være ukorrekte! Du eller andre knuder kan have behov for at opgradere. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Advarsel: Undersøg venligst, at din computers dato og klokkeslæt er korrekt indstillet! Hvis der er fejl i disse, vil CasinoCoin ikke fungere korrekt. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Advarsel: fejl under læsning af wallet.dat! Alle nøgler blev læst korrekt, men transaktionsdata eller adressebogsposter kan mangle eller være forkerte. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Advarsel: wallet.dat ødelagt, data reddet! Oprindelig wallet.net gemt som wallet.{timestamp}.bak i %s; hvis din saldo eller dine transaktioner er forkert, bør du genskabe fra en sikkerhedskopi. + + + + Attempt to recover private keys from a corrupt wallet.dat + Forsøg at genskabe private nøgler fra ødelagt wallet.dat + + + + Block creation options: + Blokoprettelsestilvalg: + + + + Connect only to the specified node(s) + Tilslut kun til de(n) angivne knude(r) + + + + Corrupted block database detected + Ødelagt blokdatabase opdaget + + + + Discover own IP address (default: 1 when listening and no -externalip) + Find egen IP-adresse (standard: 1 når lytter og ingen -externalip) + + + + Do you want to rebuild the block database now? + Ønsker du at genbygge blokdatabasen nu? + + + + Error initializing block database + Klargøring af blokdatabase mislykkedes + + + + Error initializing wallet database environment %s! + Klargøring af tegnebogsdatabasemiljøet %s mislykkedes! + + + + Error loading block database + Indlæsning af blokdatabase mislykkedes + + + + Error opening block database + Åbning af blokdatabase mislykkedes + + + + Error: Disk space is low! + Fejl: Mangel på ledig diskplads! + + + + Error: Wallet locked, unable to create transaction! + Fejl: Tegnebog låst, kan ikke oprette transaktion! + + + + Error: system error: + Fejl: systemfejl: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Lytning på enhver port mislykkedes. Brug -listen=0, hvis du ønsker dette. + + + + Failed to read block info + Læsning af blokinformation mislykkedes + + + + Failed to read block + Læsning af blok mislykkedes + + + + Failed to sync block index + Synkronisering af blokindeks mislykkedes + + + + Failed to write block index + Skrivning af blokindeks mislykkedes + + + + Failed to write block info + Skrivning af blokinformation mislykkedes + + + + Failed to write block + Skrivning af blok mislykkedes + + + + Failed to write file info + Skriving af filinformation mislykkedes + + + + Failed to write to coin database + Skrivning af casinocoin-database mislykkedes + + + + Failed to write transaction index + Skrivning af transaktionsindeks mislykkedes + + + + Failed to write undo data + Skrivning af genskabelsesdata mislykkedes + + + + Find peers using DNS lookup (default: 1 unless -connect) + Find ligeværdige ved DNS-opslag (standard: 1 hvis ikke -connect) + + + + Generate coins (default: 0) + Generer casinocoins (standard: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Antal blokke som tjekkes ved opstart (0=alle, standard: 288) + + + + How thorough the block verification is (0-4, default: 3) + Grundighed af efterprøvning af blokke (0-4, standard: 3) + + + + Not enough file descriptors available. + For få tilgængelige fildeskriptorer. + + + + Rebuild block chain index from current blk000??.dat files + Genbyg blokkædeindeks fra nuværende blk000??.dat filer + + + + Set the number of threads to service RPC calls (default: 4) + Angiv antallet af tråde til at håndtere RPC-kald (standard: 4) + + + + Verifying blocks... + Efterprøver blokke... + + + + Verifying wallet... + Efterprøver tegnebog... + + + + Imports blocks from external blk000??.dat file + Importerer blokke fra ekstern blk000??.dat fil + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Angiv nummeret af skriptefterprøvningstråde (op til 16, 0 = automatisk, <0 = efterlad det antal kerner tilgængelige, standard: 0) + + + + Information + Information + + + + Invalid -tor address: '%s' + Ugyldig -tor adresse: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ugyldigt beløb til -minrelaytxfee=<beløb>:'%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ugyldigt beløb til -mintxfee=<beløb>:'%s' + + + + Maintain a full transaction index (default: 0) + Vedligehold et komplet transaktionsindeks (standard: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maksimum for modtagelsesbuffer pr. forbindelse, <n>*1000 bytes (standard: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maksimum for afsendelsesbuffer pr. forbindelse, <n>*1000 bytes (standard: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Accepter kun blokkæde, som matcher indbyggede kontrolposter (standard: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Tilslut kun til knuder i netværk <net> (IPv4, IPv6 eller Tor) + + + + Output extra debugging information. Implies all other -debug* options + Skriv ekstra fejlsøgningsinformation. Indebærer alle andre -debug* tilvalg + + + + Output extra network debugging information + Skriv ekstra netværksfejlsøgningsinformation + + + Prepend debug output with timestamp - + Tilføj fejlsøgningsoutput med tidsstempel - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL-indstillinger: (se CasinoCoin Wiki for SSL-opsætningsinstruktioner) + + + + Select the version of socks proxy to use (4-5, default: 5) + Angiv version af SOCKS-proxyen (4-5, standard: 5) + + + Send trace/debug info to console instead of debug.log file - + Send sporings-/fejlsøgningsinformation til konsollen i stedet for debug.log filen - + Send trace/debug info to debugger - + Send sporings-/fejlsøgningsinformation til fejlsøgningprogrammet - + + Set maximum block size in bytes (default: 250000) + Angiv maksimumblokstørrelse i bytes (standard: 250000) + + + + Set minimum block size in bytes (default: 0) + Angiv minimumsblokstørrelse i bytes (standard: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Formindsk debug.log filen ved klientopstart (standard: 1 hvis ikke -debug) + + + + Signing transaction failed + Underskrift af transaktion mislykkedes + + + + Specify connection timeout in milliseconds (default: 5000) + Angiv tilslutningstimeout i millisekunder (standard: 5000) + + + + System error: + Systemfejl: + + + + Transaction amount too small + Transaktionsbeløb er for lavt + + + + Transaction amounts must be positive + Transaktionsbeløb skal være positive + + + + Transaction too large + Transaktionen er for stor + + + + Use UPnP to map the listening port (default: 0) + Forsøg at bruge UPnP til at konfigurere den lyttende port (standard: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Forsøg at bruge UPnP til at konfigurere den lyttende port (standard: 1 når lytter) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Brug proxy til at tilgå Tor Hidden Services (standard: som -proxy) + + + Username for JSON-RPC connections - Brugernavn til JSON-RPC-forbindelser - + Brugernavn til JSON-RPC-forbindelser - + + Warning + Advarsel + + + + Warning: This version is obsolete, upgrade required! + Advarsel: Denne version er forældet, opgradering påkrævet! + + + + You need to rebuild the databases using -reindex to change -txindex + Du skal genbygge databaserne med -reindex for at ændre -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat ødelagt, redning af data mislykkedes + + + Password for JSON-RPC connections - Password til JSON-RPC-forbindelser - + Adgangskode til JSON-RPC-forbindelser - - Listen for JSON-RPC connections on <port> (default: 8332) - Lyt til JSON-RPC-forbindelser på <port> (standard: 8332) - - - - + Allow JSON-RPC connections from specified IP address - Tillad JSON-RPC-forbindelser fra bestemt IP-adresse - + Tillad JSON-RPC-forbindelser fra bestemt IP-adresse - + Send commands to node running on <ip> (default: 127.0.0.1) - Send kommandoer til node, der kører på <ip> (standard: 127.0.0.1) - + Send kommandoer til knude, der kører på <ip> (standard: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Udfør kommando, når den bedste blok ændres (%s i kommandoen erstattes med blokhash) - + Upgrade wallet to latest format - + Opgrader tegnebog til seneste format - + Set key pool size to <n> (default: 100) - Sæt nøglepoolstørrelse til <n> (standard: 100) - + Angiv nøglepoolstørrelse til <n> (standard: 100) - + Rescan the block chain for missing wallet transactions - Gennemsøg blokkæden for manglende tegnebogstransaktioner - + Gennemsøg blokkæden for manglende tegnebogstransaktioner - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL-indstillinger: (se Bitcoin Wiki for SSL opsætningsinstruktioner) - - - + Use OpenSSL (https) for JSON-RPC connections - Brug OpenSSL (https) for JSON-RPC-forbindelser - + Brug OpenSSL (https) for JSON-RPC-forbindelser - + Server certificate file (default: server.cert) - Servercertifikat-fil (standard: server.cert) - + Servercertifikat-fil (standard: server.cert) - + Server private key (default: server.pem) - Server private nøgle (standard: server.pem) - + Serverens private nøgle (standard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Acceptabele ciphers (standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + Acceptable ciphers (standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message - Denne hjælpebesked - + Denne hjælpebesked - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Kan låse data-biblioteket %s. Bitcoin kører sikkert allerede. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Kunne ikke tildele %s på denne computer (bind returnerede fejl %d, %s) - + Connect through socks proxy - + Tilslut via SOCKS-proxy - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Tillad DNS-opslag for -addnode, -seednode og -connect - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Indlæser adresser... - - Error loading blkindex.dat - - - - + Error loading wallet.dat: Wallet corrupted - + Fejl ved indlæsning af wallet.dat: Tegnebog ødelagt - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Fejl ved indlæsning af wallet.dat: Tegnebog kræver en nyere version af CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - + + Wallet needed to be rewritten: restart CasinoCoin to complete + Det var nødvendigt at genskrive tegnebogen: genstart CasinoCoin for at gennemføre - + Error loading wallet.dat - + Fejl ved indlæsning af wallet.dat - + Invalid -proxy address: '%s' - + Ugyldig -proxy adresse: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Ukendt netværk anført i -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Ukendt -socks proxy-version: %i - + Cannot resolve -bind address: '%s' - + Kan ikke finde -bind adressen: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Kan ikke finde -externalip adressen: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Ugyldigt beløb for -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Fejl: Oprettelse af transaktionen mislykkedes - - - - Sending... - Sender... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Fejl: Transaktionen blev afvist. Dette kan ske hvis nogle af dine coins i din tegnebog allerede var brugt, som hvis du brugte en kopi af wallet.dat og dine coins er blevet brugt i kopien, men ikke er markeret som brugt her. - - - + Invalid amount - + Ugyldigt beløb - + Insufficient funds - Du har ikke penge nok + Manglende dækning - + Loading block index... - Indlæser blok-indeks... + Indlæser blokindeks... - + Add a node to connect to and attempt to keep the connection open - + Tilføj en knude til at forbinde til og forsøg at holde forbindelsen åben - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Kunne ikke tildele %s på denne computer. CasinoCoin kører sikkert allerede. - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - + Fee per KB to add to transactions you send - + Gebyr pr. kB, som skal tilføjes til transaktioner, du sender - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Indlæser tegnebog... - + Cannot downgrade wallet - + Kan ikke nedgradere tegnebog - - Cannot initialize keypool - - - - + Cannot write default address - + Kan ikke skrive standardadresse - + Rescanning... Genindlæser... - + Done loading Indlæsning gennemført - + To use the %s option - + For at bruge %s mulighed - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - - - - + Error - + Fejl - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Advarsel: Undersøg venligst at din computers dato og klokkeslet er korrekt indstillet. Hvis der er fejl i disse vil Bitcoin ikke fungere korrekt. + Du skal angive rpcpassword=<password> i konfigurationsfilen: +%s +Hvis filen ikke eksisterer, opret den og giv ingen andre end ejeren læserettighed. \ No newline at end of file diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 2b9aaf3..fbd2592 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - Über Bitcoin + + About CasinoCoin + Über CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> Version + + <b>CasinoCoin</b> version + <b>CasinoCoin</b>-Version - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Entwickler - + Dies ist experimentelle Software. -Veröffentlicht unter der MIT/X11 Software-Lizenz, siehe beiligende Datei license.txt oder http://www.opensource.org/licenses/mit-license.php. +Veröffentlicht unter der MIT/X11-Softwarelizenz, siehe beiligende Datei COPYING oder http://www.opensource.org/licenses/mit-license.php. -Dieses Produkt enthält Software, die vom OpenSSL Projekt zur Verwendung im OpenSSL Toolkit (http://www.openssl.org/) entwickelt wurde, sowie kryptographische Software geschrieben von Eric Young (eay@cryptsoft.com) und UPnP Software geschrieben von Thomas Bernard. +Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im OpenSSL-Toolkit (http://www.openssl.org/) entwickelt wurde, sowie kryptographische Software geschrieben von Eric Young (eay@cryptsoft.com) und UPnP-Software geschrieben von Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers + Die CasinoCoinentwickler AddressBookPage - + Address Book Adressbuch - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Dies sind Ihre Bitcoin-Adressen zum Empfangen von Zahlungen. Es steht Ihnen frei, jedem Absender eine andere mitzuteilen, um einen besseren Überblick über eingehende Zahlungen zu erhalten. - - - + Double-click to edit address or label Doppelklicken, um die Adresse oder die Bezeichnung zu bearbeiten - + Create a new address Eine neue Adresse erstellen - + Copy the currently selected address to the system clipboard Ausgewählte Adresse in die Zwischenablage kopieren - + &New Address &Neue Adresse - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Dies sind Ihre CasinoCoin-Adressen zum Empfangen von Zahlungen. Es steht Ihnen frei, jedem Absender eine Andere mitzuteilen, um einen besseren Überblick über eingehende Zahlungen zu erhalten. + + + &Copy Address Adresse &kopieren - + Show &QR Code &QR-Code anzeigen - - Sign a message to prove you own this address - Eine Nachricht signieren, um den Besitz einer Adresse zu beweisen + + Sign a message to prove you own a CasinoCoin address + Eine Nachricht signieren, um den Besitz einer CasinoCoin-Adresse zu beweisen - - &Sign Message + + Sign &Message Nachricht &signieren - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Die ausgewählte Adresse aus der Liste entfernen. Sie können nur Zahlungsadressen entfernen. + + Delete the currently selected address from the list + Die ausgewählte Adresse aus der Liste entfernen. - + + Export the data in the current tab to a file + Daten der aktuellen Ansicht in eine Datei exportieren + + + + &Export + E&xportieren + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Eine Nachricht verifizieren, um sicherzustellen, dass diese mit einer angegebenen CasinoCoin-Adresse signiert wurde + + + + &Verify Message + Nachricht &verifizieren + + + &Delete &Löschen - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Dies sind Ihre CasinoCoin-Adressen zum Tätigen von Überweisungen. Bitte prüfen Sie den Betrag und die Empfangsadresse, bevor Sie CasinoCoins überweisen. + + + Copy &Label &Bezeichnung kopieren - + &Edit &Editieren - + + Send &Coins + CasinoCoins &überweisen + + + Export Address Book Data Adressbuch exportieren - + Comma separated file (*.csv) - Kommagetrennte Datei (*.csv) + Kommagetrennte-Datei (*.csv) - + Error exporting Fehler beim Exportieren - + Could not write to file %1. Konnte nicht in Datei %1 schreiben. @@ -126,17 +164,17 @@ Dieses Produkt enthält Software, die vom OpenSSL Projekt zur Verwendung im Open AddressTableModel - + Label Bezeichnung - + Address Adresse - + (no label) (keine Bezeichnung) @@ -144,431 +182,460 @@ Dieses Produkt enthält Software, die vom OpenSSL Projekt zur Verwendung im Open AskPassphraseDialog - + Passphrase Dialog - Passphrasen Dialog + Passphrasendialog - + Enter passphrase Passphrase eingeben - + New passphrase Neue Passphrase - + Repeat new passphrase Neue Passphrase wiederholen - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Geben Sie die neue Passphrase für die Brieftasche ein.<br>Bitte benutzen Sie eine Passphrase bestehend aus <b>10 oder mehr zufälligen Zeichen</b> oder <b>8 oder mehr Wörtern</b>. - + Encrypt wallet Brieftasche verschlüsseln - + This operation needs your wallet passphrase to unlock the wallet. - Dieser Vorgang benötigt Ihre Passphrase um die Brieftasche zu entsperren. + Dieser Vorgang benötigt Ihre Passphrase, um die Brieftasche zu entsperren. - + Unlock wallet Brieftasche entsperren - + This operation needs your wallet passphrase to decrypt the wallet. - Dieser Vorgang benötigt Ihre Passphrase um die Brieftasche zu entschlüsseln. + Dieser Vorgang benötigt Ihre Passphrase, um die Brieftasche zu entschlüsseln. - + Decrypt wallet Brieftasche entschlüsseln - + Change passphrase Passphrase ändern - + Enter the old and new passphrase to the wallet. - Geben Sie die alte und die neue Passphrase der Brieftasche ein. + Geben Sie die alte und neue Passphrase der Brieftasche ein. - + Confirm wallet encryption Verschlüsselung der Brieftasche bestätigen - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - WARNUNG: Wenn Sie Ihre Brieftasche verschlüsseln und Ihre Passphrase verlieren, werden Sie <b>ALLE IHRE BITCOINS VERLIEREN</b>!<br><br>Sind Sie sich sicher, dass Sie Ihre Brieftasche verschlüsseln möchten? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Warnung: Wenn Sie Ihre Brieftasche verschlüsseln und Ihre Passphrase verlieren, werden Sie <b>alle Ihre CasinoCoins verlieren</b>! - - + + Are you sure you wish to encrypt your wallet? + Sind Sie sich sicher, dass Sie Ihre Brieftasche verschlüsseln möchten? + + + + 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. + WICHTIG: Alle vorherigen Sicherungen Ihrer Brieftasche sollten durch die neu erzeugte, verschlüsselte Brieftasche ersetzt werden. Aus Sicherheitsgründen werden vorherige Sicherungen der unverschlüsselten Brieftasche nutzlos, sobald Sie die neue, verschlüsselte Brieftasche verwenden. + + + + + Warning: The Caps Lock key is on! + Warnung: Die Feststelltaste ist aktiviert! + + + + Wallet encrypted Brieftasche verschlüsselt - - Bitcoin 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. - Bitcoin wird jetzt beendet, um den Verschlüsselungsprozess abzuschließen. Bitte beachten Sie, dass die Verschlüsselung Ihrer Brieftasche nicht vollständig vor Diebstahl Ihrer Bitcoins durch Schadsoftware schützt, die Ihren Computer befällt. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin wird jetzt beendet, um den Verschlüsselungsprozess abzuschließen. Bitte beachten Sie, dass die Verschlüsselung Ihrer Brieftasche nicht vollständig vor Diebstahl Ihrer CasinoCoins durch Schadsoftware schützt, die Ihren Computer befällt. - - - Warning: The Caps Lock key is on. - Warnung: Die Feststelltaste ist aktiviert. - - - - - - + + + + Wallet encryption failed Verschlüsselung der Brieftasche fehlgeschlagen - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Die Verschlüsselung der Brieftasche ist aufgrund eines internen Fehlers fehlgeschlagen. Ihre Brieftasche wurde nicht verschlüsselt. - - + + The supplied passphrases do not match. Die eingegebenen Passphrasen stimmen nicht überein. - + Wallet unlock failed Entsperrung der Brieftasche fehlgeschlagen - - - + + + The passphrase entered for the wallet decryption was incorrect. Die eingegebene Passphrase zum Entschlüsseln der Brieftasche war nicht korrekt. - + Wallet decryption failed Entschlüsselung der Brieftasche fehlgeschlagen - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Die Passphrase der Brieftasche wurde erfolgreich geändert. BitcoinGUI - - Bitcoin Wallet - Bitcoin-Brieftasche - - - + Sign &message... Nachricht s&ignieren... - - Show/Hide &Bitcoin - Zeige/Verstecke &Bitcoin - - - + Synchronizing with network... Synchronisiere mit Netzwerk... - + &Overview &Übersicht - + Show general overview of wallet Allgemeine Übersicht der Brieftasche anzeigen - + &Transactions &Transaktionen - + Browse transaction history Transaktionsverlauf durchsehen - - &Address Book - &Adressbuch - - - + Edit the list of stored addresses and labels Liste der gespeicherten Zahlungsadressen und Bezeichnungen bearbeiten - - &Receive coins - Bitcoins &empfangen - - - + Show the list of addresses for receiving payments Liste der Empfangsadressen anzeigen - - &Send coins - Bitcoins &überweisen - - - - Prove you control an address - Beweisen Sie die Kontrolle einer Adresse - - - + E&xit &Beenden - + Quit application Anwendung beenden - - &About %1 - &Über %1 + + Show information about CasinoCoin + Informationen über CasinoCoin anzeigen - - Show information about Bitcoin - Informationen über Bitcoin anzeigen - - - + About &Qt Über &Qt - + Show information about Qt Informationen über Qt anzeigen - + &Options... - &Erweiterte Einstellungen... + &Konfiguration... - + &Encrypt Wallet... Brieftasche &verschlüsseln... - + &Backup Wallet... Brieftasche &sichern... - + &Change Passphrase... Passphrase &ändern... - - - ~%n block(s) remaining - ~%n Block verbleibend~%n Blöcke verbleibend + + + Importing blocks from disk... + Importiere Blöcke von Laufwerk... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - %1 von %2 Blöcken des Transaktionsverlaufs heruntergeladen (%3% fertig). + + Reindexing blocks on disk... + Reindiziere Blöcke auf Laufwerk... - - &Export... - &Exportieren nach... + + Send coins to a CasinoCoin address + CasinoCoins an eine CasinoCoin-Adresse überweisen - - Send coins to a Bitcoin address - Bitcoins an eine Bitcoin-Adresse überweisen + + Modify configuration options for CasinoCoin + Die Konfiguration des Clients bearbeiten - - Modify configuration options for Bitcoin - Erweiterte Bitcoin-Einstellungen ändern - - - - Show or hide the Bitcoin window - Zeige oder verstecke das Bitcoin Fenster - - - - Export the data in the current tab to a file - Daten der aktuellen Ansicht in eine Datei exportieren - - - - Encrypt or decrypt wallet - Brieftasche ent- oder verschlüsseln - - - + Backup wallet to another location Eine Sicherungskopie der Brieftasche erstellen und abspeichern - + Change the passphrase used for wallet encryption Ändert die Passphrase, die für die Verschlüsselung der Brieftasche benutzt wird - + &Debug window - &Debug-Fenster + &Debugfenster - + Open debugging and diagnostic console - Debugging- und Diagnose-Konsole öffnen + Debugging- und Diagnosekonsole öffnen - + &Verify message... Nachricht &verifizieren... - - Verify a message signature - Eine Nachrichten-Signatur verifizieren + + + CasinoCoin + CasinoCoin - + + Wallet + Brieftasche + + + + &Send + Überweisen + + + + &Receive + &Empfangen + + + + &Addresses + &Adressen + + + + &About CasinoCoin + &Über CasinoCoin + + + + &Show / Hide + &Anzeigen / Verstecken + + + + Show or hide the main Window + Das Hauptfenster anzeigen oder verstecken + + + + Encrypt the private keys that belong to your wallet + Verschlüsselt die zu Ihrer Brieftasche gehörenden privaten Schlüssel + + + + Sign messages with your CasinoCoin addresses to prove you own them + Nachrichten signieren, um den Besitz Ihrer CasinoCoin-Adressen zu beweisen + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Nachrichten verifizieren, um sicherzustellen, dass diese mit den angegebenen CasinoCoin-Adressen signiert wurden + + + &File &Datei - + &Settings &Einstellungen - + &Help &Hilfe - + Tabs toolbar - Registerkarten-Leiste + Registerkartenleiste - - Actions toolbar - Aktionen-Werkzeugleiste - - - - + + [testnet] [Testnetz] - - - Bitcoin client - Bitcoin Client + + CasinoCoin client + CasinoCoin-Client - - %n active connection(s) to Bitcoin network - %n aktive Verbindung zum Bitcoin-Netzwerk%n aktive Verbindungen zum Bitcoin-Netzwerk + + %n active connection(s) to CasinoCoin network + %n aktive Verbindung zum CasinoCoin-Netzwerk%n aktive Verbindungen zum CasinoCoin-Netzwerk - - Downloaded %1 blocks of transaction history. - %1 Blöcke des Transaktionsverlaufs heruntergeladen. - - - - %n second(s) ago - vor %n Sekundevor %n Sekunden - - - - %n minute(s) ago - vor %n Minutevor %n Minuten - - - - %n hour(s) ago - vor %n Stundevor %n Stunden - - - - %n day(s) ago - vor %n Tagvor %n Tagen + + No block source available... + Keine Blockquelle verfügbar... - + + Processed %1 of %2 (estimated) blocks of transaction history. + %1 von (geschätzten) %2 Blöcken des Transaktionsverlaufs verarbeitet. + + + + Processed %1 blocks of transaction history. + %1 Blöcke des Transaktionsverlaufs verarbeitet. + + + + %n hour(s) + %n Stunde%n Stunden + + + + %n day(s) + %n Tag%n Tage + + + + %n week(s) + %n Woche%n Wochen + + + + %1 behind + %1 im Rückstand + + + + Last received block was generated %1 ago. + Der letzte empfangene Block ist %1 alt. + + + + Transactions after this will not yet be visible. + Transaktionen hiernach werden noch nicht angezeigt. + + + + Error + Fehler + + + + Warning + Warnung + + + + Information + Hinweis + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Die Transaktion übersteigt das Größenlimit. Sie können sie trotzdem senden, wenn Sie eine zusätzliche Transaktionsgebühr in Höhe von %1 zahlen. Diese wird an die Knoten verteilt, die Ihre Transaktion bearbeiten und unterstützt damit das CasinoCoin-Netzwerk. Möchten Sie die Gebühr bezahlen? + + + Up to date Auf aktuellem Stand - + Catching up... Hole auf... - - Last received block was generated %1. - Der letzte empfangene Block wurde %1 generiert. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Die Transaktion übersteigt das Größenlimit. Sie können sie trotzdem senden, wenn Sie eine zusätzliche Transaktionsgebühr in Höhe von %1 zahlen. Diese wird an die Knoten verteilt, die Ihre Transaktion bearbeiten und unterstützt damit das Bitcoin-Netzwerk.<br><br>Möchten Sie die Gebühr bezahlen? - - - + Confirm transaction fee Transaktionsgebühr bestätigen - + Sent transaction Gesendete Transaktion - + Incoming transaction Eingehende Transaktion - + Date: %1 Amount: %2 Type: %3 @@ -580,664 +647,632 @@ Typ: %3 Adresse: %4 - + + + URI handling + URI Verarbeitung + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI kann nicht analysiert werden! Dies kann durch eine ungültige CasinoCoin-Adresse oder fehlerhafte URI-Parameter verursacht werden. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Brieftasche ist <b>verschlüsselt</b> und aktuell <b>entsperrt</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Brieftasche ist <b>verschlüsselt</b> und aktuell <b>gesperrt</b> - - Backup Wallet - Brieftasche sichern - - - - Wallet Data (*.dat) - Brieftaschen-Datei (*.dat) - - - - Backup Failed - Sicherung der Brieftasche fehlgeschlagen - - - - There was an error trying to save the wallet data to the new location. - Fehler beim Abspeichern der Sicherungskopie der Brieftasche. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Ein schwerer Fehler ist aufgetreten. Bitcoin kann nicht stabil weiter ausgeführt werden und wird beendet. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ein schwerer Fehler ist aufgetreten. CasinoCoin kann nicht stabil weiter ausgeführt werden und wird beendet. ClientModel - + Network Alert - Netzwerk-Alarm - - - - DisplayOptionsPage - - - Display - Anzeige - - - - default - Standard - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - Legt die Sprache der Benutzeroberfläche fest. Diese Einstellung wird erst nach einem Neustart von Bitcoin aktiv. - - - - User Interface &Language: - &Sprache der Benutzeroberfläche: - - - - &Unit to show amounts in: - &Einheit der Beträge: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Wählen Sie die Standard-Untereinheit, die in der Benutzeroberfläche und beim Überweisen von Bitcoins angezeigt werden soll - - - - &Display addresses in transaction list - Adressen in der Transaktionsliste &anzeigen - - - - Whether to show Bitcoin addresses in the transaction list - Legt fest, ob Bitcoin-Addressen in der Transaktionsliste angezeigt werden - - - - Warning - Warnung - - - - This setting will take effect after restarting Bitcoin. - Diese Einstellung wird erst nach einem Neustart von Bitcoin aktiv. + Netzwerkalarm EditAddressDialog - + Edit Address Adresse bearbeiten - + &Label &Bezeichnung - + The label associated with this address book entry Die Bezeichnung dieses Adressbuchseintrags - + &Address &Adresse - + The address associated with this address book entry. This can only be modified for sending addresses. Die Adresse des Adressbucheintrags. Diese kann nur für Zahlungsadressen bearbeitet werden. - + New receiving address Neue Empfangsadresse - + New sending address Neue Zahlungsadresse - + Edit receiving address Empfangsadresse bearbeiten - + Edit sending address Zahlungsadresse bearbeiten - + The entered address "%1" is already in the address book. Die eingegebene Adresse "%1" befindet sich bereits im Adressbuch. - - The entered address "%1" is not a valid Bitcoin address. - Die eingegebene Adresse "%1" ist keine gültige Bitcoin-Adresse. + + The entered address "%1" is not a valid CasinoCoin address. + Die eingegebene Adresse "%1" ist keine gültige CasinoCoin-Adresse. - + Could not unlock wallet. Die Brieftasche konnte nicht entsperrt werden. - + New key generation failed. Generierung eines neuen Schlüssels fehlgeschlagen. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version Version - + Usage: Benutzung: - - options - Kommandozeilen-Optionen + + command-line options + Kommandozeilenoptionen - + UI options - UI Optionen + UI-Optionen - + Set language, for example "de_DE" (default: system locale) Sprache festlegen, z.B. "de_DE" (Standard: System Locale) - + Start minimized Minimiert starten - + Show splash screen on startup (default: 1) Startbildschirm beim Starten anzeigen (Standard: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Block- und Adressdatenbank beim Beenden trennen. Diese können so in ein anderes Datenverzeichnis verschoben werden, die zum Beenden benötigte Zeit wird aber verlängert. Die Datenbank der Brieftasche wird immer getrennt. + + Options + Erweiterte Einstellungen - + + &Main + &Allgemein + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optionale Transaktionsgebühr pro KB, die sicherstellt, dass Ihre Transaktionen schnell bearbeitet werden. Die meisten Transaktionen sind 1 kB groß. + + + Pay transaction &fee Transaktions&gebühr bezahlen - - Main - Allgemein + + Automatically start CasinoCoin after logging in to the system. + CasinoCoin nach der Anmeldung am System automatisch ausführen. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Optionale Transaktionsgebühr pro kB, die sicherstellt, dass Ihre Transaktionen schnell bearbeitet werden. Die meisten Transaktionen sind 1 kB groß. Eine Gebühr von 0.01 BTC wird empfohlen. + + &Start CasinoCoin on system login + &Starte CasinoCoin nach Systemanmeldung - - &Start Bitcoin on system login - &Starte Bitcoin nach Systemanmeldung + + Reset all client options to default. + Setzt die Clientkonfiguration auf Standardwerte zurück. - - Automatically start Bitcoin after logging in to the system - Bitcoin nach der Anmeldung am System automatisch ausführen + + &Reset Options + Konfiguration &zurücksetzen - - &Detach databases at shutdown - Datenbanken beim Beenden &trennen - - - - MessagePage - - - Sign Message - Nachricht signieren + + &Network + &Netzwerk - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Sie können Nachrichten mit Ihren Adressen signieren, um den Besitz dieser Adressen zu beweisen. Bitte nutzen Sie diese Funktion mit Vorsicht und nehmen Sie sich vor Phishing-Angriffen in Acht. Signieren Sie nur Nachrichten, mit denen Sie vollständig einverstanden sind. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automatisch den CasinoCoin-Clientport auf dem Router öffnen. Dies funktioniert nur, wenn Ihr Router UPnP unterstützt und dies aktiviert ist. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Die Adresse mit der die Nachricht signiert wird (z.B. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Adresse aus dem Adressbuch auswählen - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Adresse aus der Zwischenablage einfügen - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Zu signierende Nachricht hier eingeben - - - - Copy the current signature to the system clipboard - Aktuelle Signatur in die Zwischenablage kopieren - - - - &Copy Signature - Signatur &kopieren - - - - Reset all sign message fields - Alle Nachricht signieren Felder zurücksetzen - - - - Clear &All - &Zurücksetzen - - - - Click "Sign Message" to get signature - Auf "Nachricht signieren" klicken, um die Signatur zu erhalten - - - - Sign a message to prove you own this address - Die Nachricht signieren, um den Besitz der angegebenen Adresse nachzuweisen - - - - &Sign Message - Nachricht &signieren - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Bitcoin-Adresse eingeben (z.B. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Fehler beim Erzeugen der Signatur - - - - %1 is not a valid address. - %1 ist keine gültige Adresse. - - - - %1 does not refer to a key. - "%1" verweist nicht auf einen Schlüssel. - - - - Private key for %1 is not available. - Privater Schlüssel für %1 ist nicht verfügbar. - - - - Sign failed - Signierung der Nachricht fehlgeschlagen - - - - NetworkOptionsPage - - - Network - Netzwerk - - - + Map port using &UPnP Portweiterleitung via &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automatisch den Bitcoin Client-Port auf dem Router öffnen. Dies funktioniert nur, wenn Ihr Router UPnP unterstützt und dies aktiviert ist. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Über einen SOCKS-Proxy mit dem CasinoCoin-Netzwerk verbinden (z.B. beim Verbinden über Tor). - - &Connect through SOCKS4 proxy: - Über einen SOCKS4-Proxy &verbinden: + + &Connect through SOCKS proxy: + Über einen SOCKS-Proxy &verbinden: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Über einen SOCKS4-Proxy mit dem Bitcoin-Netzwerk verbinden (z.B. bei einer Verbindung über Tor) - - - + Proxy &IP: Proxy-&IP: - + + IP address of the proxy (e.g. 127.0.0.1) + IP-Adresse des Proxies (z.B. 127.0.0.1) + + + &Port: &Port: - - IP address of the proxy (e.g. 127.0.0.1) - IP-Adresse des Proxy-Servers (z.B. 127.0.0.1) + + Port of the proxy (e.g. 9050) + Port des Proxies (z.B. 9050) - - Port of the proxy (e.g. 1234) - Port des Proxy-Servers (z.B. 1234) + + SOCKS &Version: + SOCKS-&Version: - - - OptionsDialog - - Options - Erweiterte Einstellungen + + SOCKS version of the proxy (e.g. 5) + SOCKS-Version des Proxies (z.B. 5) + + + + &Window + &Programmfenster + + + + Show only a tray icon after minimizing the window. + Nur ein Symbol im Infobereich anzeigen, nachdem das Programmfenster minimiert wurde. + + + + &Minimize to the tray instead of the taskbar + In den Infobereich anstatt in die Taskleiste &minimieren + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimiert die Anwendung anstatt sie zu beenden wenn das Fenster geschlossen wird. Wenn dies aktiviert ist, müssen Sie das Programm über "Beenden" im Menü schließen. + + + + M&inimize on close + Beim Schließen m&inimieren + + + + &Display + &Anzeige + + + + User Interface &language: + &Sprache der Benutzeroberfläche: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Legt die Sprache der Benutzeroberfläche fest. Diese Einstellung wird erst nach einem Neustart von CasinoCoin aktiv. + + + + &Unit to show amounts in: + &Einheit der Beträge: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Wählen Sie die Standarduntereinheit, die in der Benutzeroberfläche und beim Überweisen von CasinoCoins angezeigt werden soll. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Legt fest, ob CasinoCoin-Adressen in der Transaktionsliste angezeigt werden. + + + + &Display addresses in transaction list + Adressen in der Transaktionsliste &anzeigen + + + + &OK + &OK + + + + &Cancel + &Abbrechen + + + + &Apply + &Übernehmen + + + + default + Standard + + + + Confirm options reset + Zurücksetzen der Konfiguration bestätigen + + + + Some settings may require a client restart to take effect. + Einige Einstellungen benötigen möglicherweise einen Clientneustart, um aktiv zu werden. + + + + Do you want to proceed? + Wollen Sie fortfahren? + + + + + Warning + Warnung + + + + + This setting will take effect after restarting CasinoCoin. + Diese Einstellung wird erst nach einem Neustart von CasinoCoin aktiv. + + + + The supplied proxy address is invalid. + Die eingegebene Proxyadresse ist ungültig. OverviewPage - + Form Formular - - - 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. - Die angezeigten Informationen sind möglicherweise nicht mehr aktuell. Ihre Brieftasche wird synchronisiert nachdem eine Verbindung zum Netzwerk hergestellt wurde, dieser Prozess ist aber derzeit noch nicht abgeschlossen. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Die angezeigten Informationen sind möglicherweise nicht mehr aktuell. Ihre Brieftasche wird automatisch synchronisiert, nachdem eine Verbindung zum CasinoCoin-Netzwerk hergestellt wurde. Dieser Prozess ist jedoch derzeit noch nicht abgeschlossen. - + Balance: Kontostand: - - Number of transactions: - Anzahl der Transaktionen: - - - + Unconfirmed: Unbestätigt: - + Wallet Brieftasche - + + Immature: + Unreif: + + + + Mined balance that has not yet matured + Erarbeiteter Betrag der noch nicht gereift ist + + + <b>Recent transactions</b> <b>Letzte Transaktionen</b> - + Your current balance Ihr aktueller Kontostand - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Betrag aus unbestätigten Transaktionen, der noch nicht im aktuellen Kontostand enthalten ist - - Total number of transactions in wallet - Anzahl aller Transaktionen in der Brieftasche - - - - + + out of sync nicht synchron + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + "casinocoin: Klicken-zum-Bezahlen"-Handler konnte nicht gestartet werden + + QRCodeDialog - + QR Code Dialog - QR-Code Dialog + QR-Code-Dialog - - QR Code - QR-Code - - - + Request Payment Zahlung anfordern - + Amount: Betrag: - - BTC - BTC - - - + Label: Bezeichnung: - + Message: Nachricht: - + &Save As... &Speichern unter... - + Error encoding URI into QR Code. Fehler beim Kodieren der URI in den QR-Code. - + + The entered amount is invalid, please check. + Der eingegebene Betrag ist ungültig, bitte überprüfen. + + + Resulting URI too long, try to reduce the text for label / message. Resultierende URI zu lang, bitte den Text für Bezeichnung / Nachricht kürzen. - + Save QR Code QR-Code abspeichern - + PNG Images (*.png) - PNG Bild (*.png) + PNG-Bild (*.png) RPCConsole - - Bitcoin debug window - Bitcoin Debug-Fenster - - - + Client name - Client Name + Clientname - - - - - - - - - + + + + + + + + + + N/A n.v. - + Client version - Client Version + Clientversion - + &Information &Information - - Client - Client + + Using OpenSSL version + Verwendete OpenSSL-Version - + Startup time Startzeit - + Network Netzwerk - + Number of connections Anzahl Verbindungen - + On testnet Im Testnetz - + Block chain Blockkette - + Current number of blocks Aktuelle Anzahl Blöcke - + Estimated total blocks Geschätzte Gesamtzahl Blöcke - + Last block time - Letzte Block-Zeit + Letzte Blockzeit - - Debug logfile - Debug-Protokolldatei - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - Öffnet die Bitcoin Debug-Protokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern. - - - + &Open &Öffnen - + + Command-line options + Kommandozeilenoptionen + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Zeige die CasinoCoin-Qt-Hilfsnachricht, um eine Liste mit möglichen Kommandozeilenoptionen zu erhalten. + + + + &Show + &Anzeigen + + + &Console &Konsole - + Build date Erstellungsdatum - + + CasinoCoin - Debug window + CasinoCoin - Debugfenster + + + + CasinoCoin Core + CasinoCoin-Kern + + + + Debug log file + Debugprotokolldatei + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Öffnet die CasinoCoin-Debugprotokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern. + + + Clear console Konsole zurücksetzen - - Welcome to the Bitcoin RPC console. - Willkommen in der Bitcoin RPC-Konsole. + + Welcome to the CasinoCoin RPC console. + Willkommen in der CasinoCoin-RPC-Konsole. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Pfeiltaste hoch und runter, um die Historie durchzublättern und <b>Strg-L</b>, um die Konsole zurückzusetzen. - + Type <b>help</b> for an overview of available commands. Bitte <b>help</b> eingeben, um eine Übersicht verfügbarer Befehle zu erhalten. @@ -1245,327 +1280,566 @@ Adresse: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Bitcoins überweisen + CasinoCoins überweisen - + Send to multiple recipients at once In einer Transaktion an mehrere Empfänger auf einmal überweisen - - &Add Recipient + + Add &Recipient Empfänger &hinzufügen - + Remove all transaction fields Alle Überweisungsfelder zurücksetzen - + Clear &All &Zurücksetzen - + Balance: Kontostand: - + 123.456 BTC 123.456 BTC - + Confirm the send action Überweisung bestätigen - - &Send + + S&end &Überweisen - + <b>%1</b> to %2 (%3) <b>%1</b> an %2 (%3) - + Confirm send coins Überweisung bestätigen - + Are you sure you want to send %1? Sind Sie sich sicher, dass Sie die folgende Überweisung ausführen möchten?<br>%1 - + and und - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen. - + The amount to pay must be larger than 0. Der zu zahlende Betrag muss größer als 0 sein. - + The amount exceeds your balance. Der angegebene Betrag übersteigt Ihren Kontostand. - + The total exceeds your balance when the %1 transaction fee is included. Der angegebene Betrag übersteigt aufgrund der Transaktionsgebühr in Höhe von %1 Ihren Kontostand. - + Duplicate address found, can only send to each address once per send operation. Doppelte Adresse gefunden, pro Überweisung kann an jede Adresse nur einmalig etwas überwiesen werden. - - Error: Transaction creation failed. - Fehler: Transaktionserstellung fehlgeschlagen. + + Error: Transaction creation failed! + Fehler: Transaktionserstellung fehlgeschlagen! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Fehler: Die Transaktion wurde abgelehnt. Dies kann passieren, wenn einige Bitcoins aus Ihrer Brieftasche bereits ausgegeben wurden. Beispielsweise weil Sie eine Kopie Ihrer wallet.dat genutzt, die Bitcoins dort ausgegeben haben und dies daher in der derzeit aktiven Brieftasche nicht vermerkt ist. + Fehler: Die Transaktion wurde abgelehnt. Dies kann passieren, wenn einige CasinoCoins aus Ihrer Brieftasche bereits ausgegeben wurden. Beispielsweise weil Sie eine Kopie Ihrer wallet.dat genutzt, die CasinoCoins dort ausgegeben haben und dies daher in der derzeit aktiven Brieftasche nicht vermerkt ist. SendCoinsEntry - + Form Formular - + A&mount: &Betrag: - + Pay &To: &Empfänger: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Die Zahlungsadresse der Überweisung (z.B. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Adressbezeichnung eingeben (diese wird zusammen mit der Adresse dem Adressbuch hinzugefügt) - + &Label: &Bezeichnung: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Die Zahlungsadresse der Überweisung (z.B. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Adresse aus Adressbuch wählen - + Alt+A Alt+A - + Paste address from clipboard Adresse aus der Zwischenablage einfügen - + Alt+P Alt+P - + Remove this recipient Diesen Empfänger entfernen - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Bitcoin-Adresse eingeben (z.B. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin-Adresse eingeben (z.B. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signaturen - eine Nachricht signieren / verifizieren + + + + &Sign Message + Nachricht &signieren + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Sie können Nachrichten mit Ihren Adressen signieren, um den Besitz dieser Adressen zu beweisen. Bitte nutzen Sie diese Funktion mit Vorsicht und nehmen Sie sich vor Phishingangriffen in Acht. Signieren Sie nur Nachrichten, mit denen Sie vollständig einverstanden sind. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Die Adresse mit der die Nachricht signiert wird (z.B. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Eine Adresse aus dem Adressbuch wählen + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Adresse aus der Zwischenablage einfügen + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Zu signierende Nachricht hier eingeben + + + + Signature + Signatur + + + + Copy the current signature to the system clipboard + Aktuelle Signatur in die Zwischenablage kopieren + + + + Sign the message to prove you own this CasinoCoin address + Die Nachricht signieren, um den Besitz dieser CasinoCoin-Adresse zu beweisen + + + + Sign &Message + &Nachricht signieren + + + + Reset all sign message fields + Alle "Nachricht signieren"-Felder zurücksetzen + + + + + Clear &All + &Zurücksetzen + + + + &Verify Message + Nachricht &verifizieren + + + + Enter the signing 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. + Geben Sie die signierende Adresse, Nachricht (achten Sie darauf Zeilenumbrüche, Leerzeichen, Tabulatoren usw. exakt zu kopieren) und Signatur unten ein, um die Nachricht zu verifizieren. Vorsicht, interpretieren Sie nicht mehr in die Signatur, als in der signierten Nachricht selber enthalten ist, um nicht von einerm Man-in-the-middle-Angriff hinters Licht geführt zu werden. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Die Adresse mit der die Nachricht signiert wurde (z.B. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Die Nachricht verifizieren, um sicherzustellen, dass diese mit der angegebenen CasinoCoin-Adresse signiert wurde + + + + Verify &Message + &Nachricht verifizieren + + + + Reset all verify message fields + Alle "Nachricht verifizieren"-Felder zurücksetzen + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin-Adresse eingeben (z.B. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Auf "Nachricht signieren" klicken, um die Signatur zu erzeugen + + + + Enter CasinoCoin signature + CasinoCoin-Signatur eingeben + + + + + The entered address is invalid. + Die eingegebene Adresse ist ungültig. + + + + + + + Please check the address and try again. + Bitte überprüfen Sie die Adresse und versuchen Sie es erneut. + + + + + The entered address does not refer to a key. + Die eingegebene Adresse verweist nicht auf einen Schlüssel. + + + + Wallet unlock was cancelled. + Entsperrung der Brieftasche wurde abgebrochen. + + + + Private key for the entered address is not available. + Privater Schlüssel zur eingegebenen Adresse ist nicht verfügbar. + + + + Message signing failed. + Signierung der Nachricht fehlgeschlagen. + + + + Message signed. + Nachricht signiert. + + + + The signature could not be decoded. + Die Signatur konnte nicht dekodiert werden. + + + + + Please check the signature and try again. + Bitte überprüfen Sie die Signatur und versuchen Sie es erneut. + + + + The signature did not match the message digest. + Die Signatur entspricht nicht dem Message Digest. + + + + Message verification failed. + Verifikation der Nachricht fehlgeschlagen. + + + + Message verified. + Nachricht verifiziert. + + + + SplashScreen + + + The CasinoCoin developers + Die CasinoCoinentwickler + + + + [testnet] + [Testnetz] TransactionDesc - - Open for %1 blocks - Offen für %1 Blöcke - - - + Open until %1 Offen bis %1 - - %1/offline? - %1/offline? + + %1/offline + %1/offline - + %1/unconfirmed %1/unbestätigt - + %1 confirmations %1 Bestätigungen - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , über %n Knoten übertragen, über %n Knoten übertragen - + + Date + Datum + + + + Source + Quelle + + + + Generated + Generiert + + + + + From + Von + + + + + + To + An + + + + + own address + eigene Adresse + + + + label + Bezeichnung + + + + + + + + Credit + Gutschrift + + + + matures in %n more block(s) + reift noch %n weiteren Blockreift noch %n weitere Blöcke + + + + not accepted + nicht angenommen + + + + + + + Debit + Belastung + + + + Transaction fee + Transaktionsgebühr + + + + Net amount + Nettobetrag + + + + Message + Nachricht signieren + + + + Comment + Kommentar + + + + Transaction ID + Transaktions-ID + + + + Generated coins must mature 120 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. + Generierte CasinoCoins müssen 120 Blöcke lang reifen, bevor sie ausgegeben werden können. Als Sie diesen Block generierten, 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 der Betrag wird nicht verfügbar werden. Das kann gelegentlich passieren, wenn ein anderer Knoten einen Block fast zeitgleich generiert. + + + + Debug information + Debuginformationen + + + + Transaction + Transaktion + + + + Inputs + Eingaben + + + + Amount + Betrag + + + + true + wahr + + + + false + falsch + + + , has not been successfully broadcast yet , wurde noch nicht erfolgreich übertragen - - - , broadcast through %1 node - , über %1 Knoten übertragen + + + Open for %n more block(s) + Offen für %n weiteren BlockOffen für %n weitere Blöcke - - , broadcast through %1 nodes - , über %1 Knoten übertragen - - - - <b>Date:</b> - <b>Datum:</b> - - - - <b>Source:</b> Generated<br> - <b>Quelle:</b> Generiert<br> - - - - - <b>From:</b> - <b>Von:</b> - - - + unknown unbekannt - - - - - <b>To:</b> - <b>An:</b> - - - - (yours, label: - (Eigene Adresse, Bezeichnung: - - - - (yours) - (Eigene Adresse) - - - - - - - <b>Credit:</b> - <b>Gutschrift:</b> - - - - (%1 matures in %2 more blocks) - %1 (reift noch %2 weitere Blöcke) - - - - (not accepted) - (nicht angenommen) - - - - - - <b>Debit:</b> - <b>Belastung:</b> - - - - <b>Transaction fee:</b> - <b>Transaktionsgebühr:</b> - - - - <b>Net amount:</b> - <b>Nettobetrag:</b> - - - - Message: - Nachricht: - - - - Comment: - Kommentar: - - - - Transaction ID: - Transaktions-ID: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Generierte Bitcoins müssen 120 Blöcke lang warten, bevor sie ausgegeben werden können. Als Sie diesen Block generierten, 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 der Betrag wird nicht verfügbar werden. Das kann gelegentlich passieren, wenn ein anderer Knoten einen Block zur selben Zeit wie Sie generierte. - TransactionDescDialog - + Transaction details Transaktionsdetails - + This pane shows a detailed description of the transaction Dieser Bereich zeigt eine detaillierte Beschreibung der Transaktion an @@ -1573,117 +1847,117 @@ Adresse: %4 TransactionTableModel - + Date Datum - + Type Typ - + Address Adresse - + Amount Betrag - - Open for %n block(s) - Offen für %n BlockOffen für %n Blöcke + + Open for %n more block(s) + Offen für %n weiteren BlockOffen für %n weitere Blöcke - + Open until %1 Offen bis %1 - + Offline (%1 confirmations) - Nicht verbunden (%1 Bestätigungen) + Offline (%1 Bestätigungen) - + Unconfirmed (%1 of %2 confirmations) Unbestätigt (%1 von %2 Bestätigungen) - + Confirmed (%1 confirmations) Bestätigt (%1 Bestätigungen) - - Mined balance will be available in %n more blocks - Der erarbeitete Betrag wird in %n Block verfügbar seinDer erarbeitete Betrag wird in %n Blöcken verfügbar sein + + Mined balance will be available when it matures in %n more block(s) + Erarbeiteter Betrag wird verfügbar sein, nachdem er noch %n weiteren Block reiftErarbeiteter Betrag wird verfügbar sein, nachdem er noch %n weitere Blöcke reift - + This block was not received by any other nodes and will probably not be accepted! Dieser Block wurde von keinem anderen Knoten empfangen und wird wahrscheinlich nicht angenommen werden! - + Generated but not accepted Generiert, jedoch nicht angenommen - + Received with Empfangen über - + Received from Empfangen von - + Sent to Überwiesen an - + Payment to yourself Eigenüberweisung - + Mined Erarbeitet - + (n/a) (k.A.) - + Transaction status. Hover over this field to show number of confirmations. Transaktionsstatus. Fahren Sie mit der Maus über dieses Feld, um die Anzahl der Bestätigungen zu sehen. - + Date and time that the transaction was received. Datum und Uhrzeit als die Transaktion empfangen wurde. - + Type of transaction. Art der Transaktion - + Destination address of transaction. - Zieladresse der Transaktion. + Zieladresse der Transaktion - + Amount removed from or added to balance. Der Betrag, der dem Kontostand abgezogen oder hinzugefügt wurde. @@ -1691,817 +1965,967 @@ Adresse: %4 TransactionView - - + + All Alle - + Today Heute - + This week Diese Woche - + This month Diesen Monat - + Last month Letzten Monat - + This year Dieses Jahr - + Range... Zeitraum... - + Received with Empfangen über - + Sent to Überwiesen an - + To yourself Eigenüberweisung - + Mined Erarbeitet - + Other Andere - + Enter address or label to search Zu suchende Adresse oder Bezeichnung eingeben - + Min amount Minimaler Betrag - + Copy address Adresse kopieren - + Copy label Bezeichnung kopieren - + Copy amount Betrag kopieren - + + Copy transaction ID + Transaktions-ID kopieren + + + Edit label Bezeichnung bearbeiten - + Show transaction details Transaktionsdetails anzeigen - + Export Transaction Data Transaktionen exportieren - + Comma separated file (*.csv) - Kommagetrennte Datei (*.csv) + Kommagetrennte-Datei (*.csv) - + Confirmed Bestätigt - + Date Datum - + Type Typ - + Label Bezeichnung - + Address Adresse - + Amount Betrag - + ID ID - + Error exporting Fehler beim Exportieren - + Could not write to file %1. Konnte nicht in Datei %1 schreiben. - + Range: Zeitraum: - + to bis - - VerifyMessageDialog - - - Verify Signed Message - Signierte Nachricht verifizieren - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - Geben Sie die Nachricht und Signatur unten ein (achten Sie besonders darauf Zeilenumbrüche, Leerzeichen, Tabulatoren und andere unsichtbare Zeichen mit zu kopieren), um die Bitcoin-Adresse zu erhalten, die zum signieren der Nachricht verwendet wurde. - - - - Verify a message and obtain the Bitcoin address used to sign the message - Eine Nachricht verifizieren und die Bitcoin-Addresse erhalten, die zum Signieren der Nachricht verwendet wurde - - - - &Verify Message - Nachricht &verifizieren - - - - Copy the currently selected address to the system clipboard - Ausgewählte Adresse in die Zwischenablage kopieren - - - - &Copy Address - Adresse &kopieren - - - - Reset all verify message fields - Alle Nachricht verifizieren Felder zurücksetzen - - - - Clear &All - &Zurücksetzen - - - - Enter Bitcoin signature - Bitcoin-Signatur eingeben - - - - Click "Verify Message" to obtain address - Auf "Nachricht verifizieren" klicken, um die Adresse zu erhalten - - - - - Invalid Signature - Signatur fehlerhaft - - - - The signature could not be decoded. Please check the signature and try again. - Die Signatur konnte nicht dekodiert werden. Bitte überprüfen Sie die Signatur und versuchen Sie es erneut. - - - - The signature did not match the message digest. Please check the signature and try again. - Die Signatur entspricht nicht dem Message Digest. Bitte überprüfen Sie die Signatur und versuchen Sie es erneut. - - - - Address not found in address book. - Adresse nicht im Adressbuch gefunden. - - - - Address found in address book: %1 - Adresse im Adressbuch gefunden: %1 - - WalletModel - - Sending... - Überweise... + + Send Coins + CasinoCoins überweisen - WindowOptionsPage + WalletView - - Window - Programmfenster + + &Export + E&xportieren - - &Minimize to the tray instead of the taskbar - In den Infobereich anstatt in die Taskleiste &minimieren + + Export the data in the current tab to a file + Daten der aktuellen Ansicht in eine Datei exportieren - - Show only a tray icon after minimizing the window - Nur ein Symbol im Infobereich anzeigen, nachdem das Fenster minimiert wurde + + Backup Wallet + Brieftasche sichern - - M&inimize on close - Beim Schließen m&inimieren + + Wallet Data (*.dat) + Brieftaschendaten (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimiert die Anwendung anstatt sie zu beenden wenn das Fenster geschlossen wird. Wenn dies aktiviert ist, müssen Sie das Programm über "Beenden" im Menü schließen. + + Backup Failed + Sicherung fehlgeschlagen + + + + There was an error trying to save the wallet data to the new location. + Beim Speichern der Brieftaschendaten an die neue Position ist ein Fehler aufgetreten. + + + + Backup Successful + Sicherung erfolgreich + + + + The wallet data was successfully saved to the new location. + Speichern der Brieftaschendaten an die neue Position war erfolgreich. bitcoin-core - - Bitcoin version - Bitcoin Version + + CasinoCoin version + CasinoCoin-Version - + Usage: Benutzung: - - Send command to -server or bitcoind - Befehl an -server oder bitcoind senden + + Send command to -server or casinocoind + Befehl an -server oder casinocoind senden - + List commands Befehle auflisten - + Get help for a command Hilfe zu einem Befehl erhalten - + Options: Optionen: - - Specify configuration file (default: bitcoin.conf) - Konfigurationsdatei angeben (Standard: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Konfigurationsdatei festlegen (Standard: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - PID-Datei angeben (Standard: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + PID-Datei festlegen (Standard: casinocoind.pid) - - Generate coins - Bitcoins generieren - - - - Don't generate coins - Keine Bitcoins generieren - - - + Specify data directory - Datenverzeichnis angeben + Datenverzeichnis festlegen - + Set database cache size in megabytes (default: 25) - Größe des Datenbank-Caches in MB festlegen (Standard: 25) + Größe des Datenbankcaches in MB festlegen (Standard: 25) - - Set database disk log size in megabytes (default: 100) - Größe der Datenbank-Logs auf der Festplatte in MB festlegen (Standard: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + <port> nach Verbindungen abhören (Standard: 47950 oder Testnetz: 17950) - - Specify connection timeout (in milliseconds) - Verbindungs-Zeitüberschreitung angeben (in Millisekunden) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - <port> nach Verbindunden abhören (Standard: 8333 oder Testnetz: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Maximal <n> Verbindungen zu Gegenstellen aufrechterhalten (Standard: 125) - - Connect only to the specified node - Nur mit dem angegebenem Knoten verbinden - - - + Connect to a node to retrieve peer addresses, and disconnect - Mit dem Knoten verbinden um Peer-Adressen abzufragen, danach trennen + Mit dem Knoten verbinden um Adressen von Gegenstellen abzufragen, danach trennen - + Specify your own public address - Die eigene öffentliche Addresse angeben + Die eigene öffentliche Adresse angeben - - Only connect to nodes in network <net> (IPv4 or IPv6) - Verbinde nur zu Knoten im Netzwerk <net> (IPv4 oder IPv6) - - - - Try to discover public IP address (default: 1) - Versuche die öffentliche IP-Adresse zu erkennen (Standard: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - An die angegebene Adresse binden. Benutze [Host]:Port Schreibweise für IPv6 - - - + Threshold for disconnecting misbehaving peers (default: 100) Schwellenwert, um Verbindungen zu sich nicht konform verhaltenden Gegenstellen zu beenden (Standard: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Anzahl Sekunden, während denen sich nicht konform verhaltenden Gegenstellen die Wiederverbindung verweigert wird (Standard: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maximale Größe, <n> * 1000 Byte, des Empfangspuffers pro Verbindung (Standard: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Beim Einrichten des abzuhörenden RPC-Ports %u für IPv4 ist ein Fehler aufgetreten: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maximale Größe, <n> * 1000 Byte, des Sendepuffers pro Verbindung (Standard: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + <port> nach JSON-RPC-Verbindungen abhören (Standard: 47970 oder Testnetz: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - Block- und Adressdatenbank beim Beenden trennen.Verlängert, die zum Beenden benötigte Zeit (Standard: 0) - - - + Accept command line and JSON-RPC commands - Kommandozeilenbefehle und JSON-RPC Befehle annehmen + Kommandozeilenbefehle und JSON-RPC-Befehle annehmen - + Run in the background as a daemon and accept commands Als Hintergrunddienst starten und Befehle annehmen - + Use the test network - Das test-Netzwerk verwenden + Das Testnetz verwenden - - Output extra debugging information - Ausgabe zusätzlicher Debugging-Informationen + + Accept connections from outside (default: 1 if no -proxy or -connect) + Eingehende Verbindungen annehmen (Standard: 1, wenn nicht -proxy oder -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, Sie müssen den Wert rpcpasswort in dieser Konfigurationsdatei angeben: +%s +Es wird empfohlen das folgende Zufallspasswort zu verwenden: +rpcuser=casinocoinrpc +rpcpassword=%s +(Sie müssen sich dieses Passwort nicht merken!) +Der Benutzername und das Passwort dürfen NICHT identisch sein. +Falls die Konfigurationsdatei nicht existiert, erzeugen Sie diese bitte mit Leserechten nur für den Dateibesitzer. +Es wird ebenfalls empfohlen alertnotify anzugeben, um im Problemfall benachrichtig zu werden; +zum Beispiel: alertnotify=echo %%s | mail -s \"CasinoCoin Alert\" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Beim Einrichten des abzuhörenden RPC-Ports %u für IPv6 ist ein Fehler aufgetreten, es wird auf IPv4 zurückgegriffen: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + An die angegebene Adresse binden und immer abhören. Für IPv6 [Host]:Port-Schreibweise verwenden + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde CasinoCoin bereits gestartet. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Fehler: Die Transaktion wurde abgelehnt! Dies kann passieren, wenn einige CasinoCoins aus Ihrer Brieftasche bereits ausgegeben wurden. Beispielsweise weil Sie eine Kopie Ihrer wallet.dat genutzt, die CasinoCoins dort ausgegeben haben und dies daher in der derzeit aktiven Brieftasche nicht vermerkt ist. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Fehler: Diese Transaktion benötigt aufgrund ihres Betrags, ihrer Komplexität oder der Nutzung kürzlich erhaltener Zahlungen eine Transaktionsgebühr in Höhe von mindestens %s! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Kommando ausführen wenn ein relevanter Alarm empfangen wird (%s im Kommando wird durch die Nachricht ersetzt) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Kommando ausführen wenn sich eine Transaktion der Briefrasche verändert (%s im Kommando wird durch die TxID ersetzt) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Maximale Größe von "high-priority/low-fee"-Transaktionen in Byte festlegen (Standard: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Dies ist eine Vorab-Testversion - Verwendung auf eigene Gefahr - nicht für Mining- oder Handelsanwendungen nutzen! + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Warnung: -paytxfee ist auf einen sehr hohen Wert festgelegt! Dies ist die Gebühr die beim Senden einer Transaktion fällig wird. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Warnung: Angezeigte Transaktionen sind evtl. nicht korrekt! Sie oder die anderen Knoten müssen unter Umständen (den Client) aktualisieren. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Warnung: Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da CasinoCoin ansonsten nicht ordnungsgemäß funktionieren wird! + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Warnung: Lesen von wallet.dat fehlgeschlagen! Alle Schlüssel wurden korrekt gelesen, Transaktionsdaten bzw. Adressbucheinträge fehlen aber möglicherweise oder sind inkorrekt. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Warnung: wallet.dat beschädigt, Rettung erfolgreich! Original wallet.dat wurde als wallet.{Zeitstempel}.dat in %s gespeichert. Falls Ihr Kontostand oder Transaktionen nicht korrekt sind, sollten Sie von einer Datensicherung wiederherstellen. + + + + Attempt to recover private keys from a corrupt wallet.dat + Versucht private Schlüssel aus einer beschädigten wallet.dat wiederherzustellen + + + + Block creation options: + Blockerzeugungsoptionen: + + + + Connect only to the specified node(s) + Nur mit dem/den angegebenen Knoten verbinden + + + + Corrupted block database detected + Beschädigte Blockdatenbank erkannt + + + + Discover own IP address (default: 1 when listening and no -externalip) + Eigene IP-Adresse erkennen (Standard: 1, wenn abgehört wird und nicht -externalip) + + + + Do you want to rebuild the block database now? + Möchten Sie die Blockdatenbank nun neu aufbauen? + + + + Error initializing block database + Fehler beim Initialisieren der Blockdatenbank + + + + Error initializing wallet database environment %s! + Fehler beim Initialisieren der Brieftaschen-Datenbankumgebung %s! + + + + Error loading block database + Fehler beim Laden der Blockdatenbank + + + + Error opening block database + Fehler beim Öffnen der Blockdatenbank + + + + Error: Disk space is low! + Fehler: Zu wenig freier Laufwerksspeicherplatz! + + + + Error: Wallet locked, unable to create transaction! + Fehler: Brieftasche gesperrt, Transaktion kann nicht erstellt werden! + + + + Error: system error: + Fehler: Systemfehler: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Fehler, es konnte kein Port abgehört werden. Wenn dies so gewünscht wird -listen=0 verwenden. + + + + Failed to read block info + Lesen der Blockinformationen fehlgeschlagen + + + + Failed to read block + Lesen des Blocks fehlgeschlagen + + + + Failed to sync block index + Synchronisation des Blockindex fehlgeschlagen + + + + Failed to write block index + Schreiben des Blockindex fehlgeschlagen + + + + Failed to write block info + Schreiben der Blockinformationen fehlgeschlagen + + + + Failed to write block + Schreiben des Blocks fehlgeschlagen + + + + Failed to write file info + Schreiben der Dateiinformationen fehlgeschlagen + + + + Failed to write to coin database + Schreiben in die Münzendatenbank fehlgeschlagen + + + + Failed to write transaction index + Schreiben des Transaktionsindex fehlgeschlagen + + + + Failed to write undo data + Schreiben der Rücksetzdaten fehlgeschlagen + + + + Find peers using DNS lookup (default: 1 unless -connect) + Gegenstellen via DNS-Namensauflösung finden (Standard: 1, außer bei -connect) + + + + Generate coins (default: 0) + CasinoCoins generieren (Standard: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Wieviele Blöcke sollen beim Starten geprüft werden (Standard: 288, 0 = alle) + + + + How thorough the block verification is (0-4, default: 3) + Wie gründlich soll die Blockprüfung sein (0-4, Standard: 3) + + + + Not enough file descriptors available. + Nicht genügend File-Deskriptoren verfügbar. + + + + Rebuild block chain index from current blk000??.dat files + Blockkettenindex aus aktuellen Dateien blk000??.dat wiederaufbauen + + + + Set the number of threads to service RPC calls (default: 4) + Maximale Anzahl an Threads zur Verarbeitung von RPC-Anfragen festlegen (Standard: 4) + + + + Verifying blocks... + Verifiziere Blöcke... + + + + Verifying wallet... + Verifiziere Brieftasche... + + + + Imports blocks from external blk000??.dat file + Blöcke aus externer Datei blk000??.dat importieren + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (bis zu 16, 0 = automatisch, <0 = soviele Kerne frei lassen, Standard: 0) + + + + Information + Hinweis + + + + Invalid -tor address: '%s' + Ungültige Adresse in -tor: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ungültiger Betrag für -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ungültiger Betrag für -mintxfee=<amount>: '%s' + + + + Maintain a full transaction index (default: 0) + Einen vollständigen Transaktionsindex pflegen (Standard: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maximale Größe, <n> * 1000 Byte, des Empfangspuffers pro Verbindung (Standard: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maximale Größe, <n> * 1000 Byte, des Sendepuffers pro Verbindung (Standard: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Blockkette nur akzeptieren, wenn sie mit den integrierten Prüfpunkten übereinstimmt (Standard: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Verbinde nur zu Knoten des Netztyps <net> (IPv4, IPv6 oder Tor) + + + + Output extra debugging information. Implies all other -debug* options + Ausgabe zusätzlicher Debugginginformationen. Beinhaltet alle anderen "-debug*"-Parameter + + + + Output extra network debugging information + Ausgabe zusätzlicher Netzwerk-Debugginginformationen + + + Prepend debug output with timestamp - Der Debug-Ausgabe einen Zeitstempel voranstellen + Der Debugausgabe einen Zeitstempel voranstellen - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL-Optionen: (siehe CasinoCoin-Wiki für SSL-Installationsanweisungen) + + + + Select the version of socks proxy to use (4-5, default: 5) + SOCKS-Version des Proxies festlegen (4-5, Standard: 5) + + + Send trace/debug info to console instead of debug.log file - Rückverfolgungs- und Debug-Informationen an die Konsole senden anstatt sie in die debug.log Datei zu schreiben + Rückverfolgungs- und Debuginformationen an die Konsole senden anstatt sie in die Datei debug.log zu schreiben - + Send trace/debug info to debugger - Rückverfolgungs- und Debug-Informationen an den Debugger senden + Rückverfolgungs- und Debuginformationen an den Debugger senden - + + Set maximum block size in bytes (default: 250000) + Maximale Blockgröße in Byte festlegen (Standard: 250000) + + + + Set minimum block size in bytes (default: 0) + Minimale Blockgröße in Byte festlegen (Standard: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Verkleinere Datei debug.log beim Start des Clients (Standard: 1, wenn kein -debug) + + + + Signing transaction failed + Signierung der Transaktion fehlgeschlagen + + + + Specify connection timeout in milliseconds (default: 5000) + Verbindungstimeout in Millisekunden festlegen (Standard: 5000) + + + + System error: + Systemfehler: + + + + Transaction amount too small + Transaktionsbetrag zu gering + + + + Transaction amounts must be positive + Transaktionsbeträge müssen positiv sein + + + + Transaction too large + Transaktion zu groß + + + + Use UPnP to map the listening port (default: 0) + UPnP verwenden, um die Portweiterleitung einzurichten (Standard: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + UPnP verwenden, um die Portweiterleitung einzurichten (Standard: 1, wenn abgehört wird) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Proxy verwenden, um versteckte Tor-Dienste zu erreichen (Standard: identisch mit -proxy) + + + Username for JSON-RPC connections - Benutzername für JSON-RPC Verbindungen + Benutzername für JSON-RPC-Verbindungen - + + Warning + Warnung + + + + Warning: This version is obsolete, upgrade required! + Warnung: Diese Version is veraltet, Aktualisierung erforderlich! + + + + You need to rebuild the databases using -reindex to change -txindex + Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um -txindex zu verändern. + + + + wallet.dat corrupt, salvage failed + wallet.dat beschädigt, Rettung fehlgeschlagen + + + Password for JSON-RPC connections - Passwort für JSON-RPC Verbindungen + Passwort für JSON-RPC-Verbindungen - - Listen for JSON-RPC connections on <port> (default: 8332) - <port> nach JSON-RPC Verbindungen abhören (Standard: 8332) - - - + Allow JSON-RPC connections from specified IP address - JSON-RPC Verbindungen von der angegebenen IP-Adresse erlauben + JSON-RPC-Verbindungen von der angegebenen IP-Adresse erlauben - + Send commands to node running on <ip> (default: 127.0.0.1) Sende Befehle an Knoten <ip> (Standard: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Kommando ausführen wenn der beste Block wechselt (%s im Kommando wird durch den Hash des Blocks ersetzt) - + Upgrade wallet to latest format Brieftasche auf das neueste Format aktualisieren - + Set key pool size to <n> (default: 100) Größe des Schlüsselpools festlegen auf <n> (Standard: 100) - + Rescan the block chain for missing wallet transactions Blockkette erneut nach fehlenden Transaktionen der Brieftasche durchsuchen - - How many blocks to check at startup (default: 2500, 0 = all) - Wieviele Blöcke sollen beim Starten geprüft werden (Standard: 2500, 0 = alle) - - - - How thorough the block verification is (0-6, default: 1) - Wie gründlich soll die Blockprüfung sein (0-6, Standard: 1) - - - - Imports blocks from external blk000?.dat file - Blöcke aus einer externen blk000?.dat Datei importieren - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL Optionen: (siehe Bitcoin-Wiki für SSL Installationsanweisungen) - - - + Use OpenSSL (https) for JSON-RPC connections - OpenSSL (https) für JSON-RPC Verbindungen verwenden + OpenSSL (https) für JSON-RPC-Verbindungen verwenden - + Server certificate file (default: server.cert) Serverzertifikat (Standard: server.cert) - + Server private key (default: server.pem) Privater Serverschlüssel (Standard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akzeptierte Chiffren (Standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - Warnung: Nicht mehr genügend Festplattenplatz verfügbar - - - + This help message Dieser Hilfetext - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde Bitcoin bereits gestartet. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) Kann auf diesem Computer nicht an %s binden (von bind zurückgegebener Fehler %d, %s) - + Connect through socks proxy - Über einen SOCKS-Proxy verbinden + Verbindung über SOCKS-Proxy herstellen - - Select the version of socks proxy to use (4 or 5, 5 is default) - Wählen, welche Version des SOCKS-Proxys genutzt werden soll (4 oder 5, 5 ist Standard) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - Keinen Proxy verwenden für Verbindungen zum Netzwerk <net> (IPv4 oder IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect Erlaube DNS-Namensauflösung für -addnode, -seednode und -connect - - Pass DNS requests to (SOCKS5) proxy - DNS-Anfragen an (SOCKS5-) Proxy weiterleiten - - - + Loading addresses... Lade Adressen... - - Error loading blkindex.dat - Fehler beim Laden von blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Fehler beim Laden von wallet.dat: Brieftasche beschädigt - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Fehler beim Laden von wallet.dat: Brieftasche benötigt neuere Version von Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Fehler beim Laden von wallet.dat: Brieftasche benötigt neuere Version von CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Brieftasche muss neu geschrieben werden: Starten Sie Bitcoin zur Fertigstellung neu + + Wallet needed to be rewritten: restart CasinoCoin to complete + Brieftasche musste neu geschrieben werden: Starten Sie CasinoCoin zur Fertigstellung neu - + Error loading wallet.dat Fehler beim Laden von wallet.dat (Brieftasche) - + Invalid -proxy address: '%s' - Ungültige -proxy Addresse: '%s' + Ungültige Adresse in -proxy: '%s' - - Unknown network specified in -noproxy: '%s' - Unbekanntes Netzwerk in -noproxy angegeben: '%s' - - - + Unknown network specified in -onlynet: '%s' - Unbekanntes Netzwerk in -onlynet angegeben: '%s' + Unbekannter Netztyp in -onlynet angegeben: '%s' - + Unknown -socks proxy version requested: %i - Unbekannte -socks Proxy Version angefordert: %i + Unbekannte Proxyversion in -socks angefordert: %i - + Cannot resolve -bind address: '%s' - Kann -bind Adresse nicht auflösen: '%s' + Kann Adresse in -bind nicht auflösen: '%s' - - Not listening on any port - Es wird kein Port nach Verbindungen abgehört - - - + Cannot resolve -externalip address: '%s' - Kann -externalip Adresse nicht auflösen: '%s' + Kann Adresse in -externalip nicht auflösen: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - Falscher Betrag für -paytxfee=<Betrag>: '%s' + Ungültiger Betrag für -paytxfee=<amount>: '%s' - - Error: could not start node - Fehler: Knoten konnte nicht gestartet weden - - - - Error: Wallet locked, unable to create transaction - Fehler: Brieftasche gesperrt, Transaktion kann nicht erstellt werden - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Fehler: Diese Transaktion benötigt aufgrund ihres Betrags, ihrer Komplexität oder der Nutzung kürzlich erhaltener Zahlungen eine Transaktionsgebühr in Höhe von mindestens %s. - - - - Error: Transaction creation failed - Fehler: Transaktionserstellung fehlgeschlagen - - - - Sending... - Senden... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Fehler: Die Transaktion wurde abgelehnt. Dies kann passieren, wenn einige Bitcoins aus Ihrer Brieftasche bereits ausgegeben wurden. Beispielsweise weil Sie eine Kopie Ihrer wallet.dat genutzt, die Bitcoins dort ausgegeben haben und dies daher in der derzeit aktiven Brieftasche nicht vermerkt ist. - - - + Invalid amount - Ungültige Angabe + Ungültiger Betrag - + Insufficient funds Unzureichender Kontostand - + Loading block index... Lade Blockindex... - + Add a node to connect to and attempt to keep the connection open Mit dem Knoten verbinden und versuchen die Verbindung aufrecht zu halten - - Unable to bind to %s on this computer. Bitcoin is probably already running. - Kann auf diesem Computer nicht an %s binden. Evtl. wurde Bitcoin bereits gestartet. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Kann auf diesem Computer nicht an %s binden. Evtl. wurde CasinoCoin bereits gestartet. - - Find peers using internet relay chat (default: 0) - Gegenstellen via Internet Relay Chat finden (Standard: 0) - - - - Accept connections from outside (default: 1) - Eingehende Verbindungen annehmen (Standard: 1) - - - - Find peers using DNS lookup (default: 1) - Gegenstellen via DNS Namensauflösung finden (Standard: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - UPnP verwenden, um die Portweiterleitung einzurichten (Standard: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - UPnP verwenden, um die Portweiterleitung einzurichten (Standard: 0) - - - + Fee per KB to add to transactions you send Gebühr pro KB, die gesendeten Transaktionen hinzugefügt wird - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - Warnung: -paytxfee ist auf einen sehr hohen Wert festgelegt. Dies ist die Gebühr die beim Senden einer Transaktion fällig wird. - - - + Loading wallet... - Lade Geldbörse... + Lade Brieftasche... - + Cannot downgrade wallet Brieftasche kann nicht auf eine ältere Version herabgestuft werden - - Cannot initialize keypool - Schlüsselpool kann nicht initialisiert werden - - - + Cannot write default address Standardadresse kann nicht geschrieben werden - + Rescanning... Durchsuche erneut... - + Done loading Laden abgeschlossen - + To use the %s option Zur Nutzung der %s Option - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, Sie müssen den Wert rpcpasswort in der Konfigurationsdatei angeben -%s -Es wird empfohlen das folgende Zufallspasswort zu verwenden: -rpcuser=bitcoinrpc -rpcpassword=%s -(Sie müssen sich dieses Passwort nicht merken!) -Falls die Konfigurationsdatei nicht existiert, erzeugen Sie diese bitte mit Leserechten nur für den Dateibesitzer. - - - - + Error Fehler - - An error occured while setting up the RPC port %i for listening: %s - Fehler beim Einrichten des RPC-Ports %i: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2509,10 +2933,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Falls die Konfigurationsdatei nicht existiert, erzeugen Sie diese bitte mit Leserechten nur für den Dateibesitzer. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Warnung: Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da Bitcoin ansonsten nicht ordnungsgemäß funktionieren wird. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 2058e1a..9b52fde 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -3,140 +3,178 @@ AboutDialog - - About Bitcoin - Σχετικα:Bitcoin + + About CasinoCoin + Σχετικά με το CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b>έκδοση + + <b>CasinoCoin</b> version + Έκδοση CasinoCoin - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Προγραμματιστές του Bitcoin + +This is experimental software. -Αυτό ειναι πειραματικο λογισμικο. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. -Διανέμεται κατω από άδεια MIT/X11 , δες το συνοδεύων αρχειο license.txt ή http://www.opensource.org/licenses/mit-license.php. - -Αυτό προϊόν περιλαμβάνει λογισμικο ανεπτυγμενο από το OpenSSL Project για χρήση στο OpenSSL Toolkit (http://www.openssl.org/) και κρυπτογραφικο κωδικα γραμένο από τον by Eric Young (eay@cryptsoft.com) και λογισμικο UPnP γραμένο από τον Thomas Bernard. +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + Copyright + Πνευματική ιδιοκτησία + + + + The CasinoCoin developers + Οι CasinoCoin προγραμματιστές AddressBookPage - + Address Book Βιβλίο Διευθύνσεων - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Αυτές είναι οι διευθύνσεις Bitcoin για την παραλαβή πληρωμών. Μπορεί να θέλετε να δίνετε διαφορετική διεύθυνση σε κάθε αποστολέα έτσι ώστε να μπορείτε να παρακολουθείτε ποιος σας πληρώνει. - - - + Double-click to edit address or label Διπλό-κλικ για επεξεργασία της διεύθυνσης ή της ετικέτας - + Create a new address Δημιούργησε νέα διεύθυνση - + Copy the currently selected address to the system clipboard Αντέγραψε την επιλεγμένη διεύθυνση στο πρόχειρο του συστήματος - + &New Address - + &Νέα διεύθυνση - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Αυτές είναι οι CasinoCoin διευθύνσεις σας για να λαμβάνετε πληρωμές. Δίνοντας μία ξεχωριστή διεύθυνση σε κάθε αποστολέα, θα μπορείτε να ελέγχετε ποιος σας πληρώνει. + + + &Copy Address - + &Αντιγραφή διεύθυνσης - + Show &QR Code Δείξε &QR κωδικα - - Sign a message to prove you own this address - Υπέγραψε ένα μήνυμα για να αποδείξεις ότι σου ανήκει η διεύθυνση + + Sign a message to prove you own a CasinoCoin address + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως σας ανήκει μια συγκεκριμένη διεύθυνση CasinoCoin - - &Sign Message + + Sign &Message &Υπέγραψε το μήνυμα - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Διέγραψε την επιλεγμένη διεύθυνση από την λίστα. Μόνο διευθύνσεις αποστολής μπορούν να διαγραφούν. + + Delete the currently selected address from the list + Αντιγραφη της επιλεγμενης διεύθυνσης στο πρόχειρο του συστηματος - + + Export the data in the current tab to a file + Εξαγωγή δεδομένων καρτέλας σε αρχείο + + + + &Export + &Εξαγωγή + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως ανήκει μια συγκεκριμένη διεύθυνση CasinoCoin + + + + &Verify Message + &Επιβεβαίωση μηνύματος + + + &Delete &Διαγραφή - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Αυτές είναι οι CasinoCoin διευθύνσεις σας για να λαμβάνετε πληρωμές. Δίνοντας μία ξεχωριστή διεύθυνση σε κάθε αποστολέα, θα μπορείτε να ελέγχετε ποιος σας πληρώνει. + + + Copy &Label - + Αντιγραφή &επιγραφής - + &Edit - + &Επεξεργασία - + + Send &Coins + Αποστολή νομισμάτων + + + Export Address Book Data Εξαγωγή Δεδομενων Βιβλίου Διευθύνσεων - + Comma separated file (*.csv) Αρχείο οριοθετημένο με κόμματα (*.csv) - + Error exporting Εξαγωγή λαθών - + Could not write to file %1. - Δεν μπόρεσα να γράψω στο αρχείο %1. + Αδυναμία εγγραφής στο αρχείο %1. AddressTableModel - + Label Ετικέτα - + Address Διεύθυνση - + (no label) (χωρίς ετικέτα) @@ -144,434 +182,463 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Φράση πρόσβασης - + Enter passphrase Βάλτε κωδικό πρόσβασης - + New passphrase Νέος κωδικός πρόσβασης - + Repeat new passphrase Επανέλαβε τον νέο κωδικό πρόσβασης - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Εισάγετε τον νέο κωδικό πρόσβασης στον πορτοφόλι <br/> Παρακαλώ χρησιμοποιείστε ένα κωδικό με <b> 10 ή περισσότερους τυχαίους χαρακτήρες</b> ή <b> οχτώ ή παραπάνω λέξεις</b>. - + Encrypt wallet Κρυπτογράφησε το πορτοφόλι - + This operation needs your wallet passphrase to unlock the wallet. Αυτη η ενεργεία χρειάζεται τον κωδικό του πορτοφολιού για να ξεκλειδώσει το πορτοφόλι. - + Unlock wallet Ξεκλειδωσε το πορτοφολι - + This operation needs your wallet passphrase to decrypt the wallet. Αυτη η ενεργεια χρειάζεται τον κωδικο του πορτοφολιου για να αποκρυπτογραφησειι το πορτοφολι. - + Decrypt wallet Αποκρυπτογράφησε το πορτοφολι - + Change passphrase Άλλαξε κωδικο πρόσβασης - + Enter the old and new passphrase to the wallet. Εισάγετε τον παλιό και τον νεο κωδικο στο πορτοφολι. - + Confirm wallet encryption Επιβεβαίωσε την κρυπτογραφηση του πορτοφολιού - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - Προσοχη: Εαν κρυπτογραφησεις το πορτοφολι σου και χάσεις τον κωδικο σου θα χάσεις <b> ΟΛΑ ΣΟΥ ΤΑ BITCOINS</b>! + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Προσοχη: Εαν κρυπτογραφησεις το πορτοφολι σου και χάσεις τον κωδικο σου θα χάσεις <b> ΟΛΑ ΣΟΥ ΤΑ CASINOCOINS</b>! Είσαι σίγουρος ότι θέλεις να κρυπτογραφησεις το πορτοφολι; - - + + Are you sure you wish to encrypt your wallet? + Είστε σίγουροι ότι θέλετε να κρυπτογραφήσετε το πορτοφόλι σας; + + + + 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. + ΣΗΜΑΝΤΙΚΟ: Τα προηγούμενα αντίγραφα ασφαλείας που έχετε κάνει από το αρχείο του πορτοφόλιου σας θα πρέπει να αντικατασταθουν με το νέο που δημιουργείται, κρυπτογραφημένο αρχείο πορτοφόλιου. Για λόγους ασφαλείας, τα προηγούμενα αντίγραφα ασφαλείας του μη κρυπτογραφημένου αρχείου πορτοφόλιου θα καταστουν άχρηστα μόλις αρχίσετε να χρησιμοποιείτε το νέο κρυπτογραφημένο πορτοφόλι. + + + + + Warning: The Caps Lock key is on! + Προσοχη: το πλήκτρο Caps Lock είναι ενεργο. + + + + Wallet encrypted Κρυπτογραφημενο πορτοφολι - - Bitcoin 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. - Το Bitcoin θα κλεισει τώρα για να τελειώσει την διαδικασία κρυπτογραφησης. Θυμησου ότι κρυπτογραφώντας το πορτοφολι σου δεν μπορείς να προστατέψεις πλήρως τα bitcoins σου από κλοπή στην περίπτωση όπου μολυνθεί ο υπολογιστής σου με κακόβουλο λογισμικο. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + Το CasinoCoin θα κλεισει τώρα για να τελειώσει την διαδικασία κρυπτογραφησης. Θυμησου ότι κρυπτογραφώντας το πορτοφολι σου δεν μπορείς να προστατέψεις πλήρως τα casinocoins σου από κλοπή στην περίπτωση όπου μολυνθεί ο υπολογιστής σου με κακόβουλο λογισμικο. - - - Warning: The Caps Lock key is on. - Προσοχη: το πλήκτρο Caps Lock είναι ενεργο. - - - - - - + + + + Wallet encryption failed Η κρυπτογραφηση του πορτοφολιού απέτυχε - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Η κρυπτογράφηση του πορτοφολιού απέτυχε λογω εσωτερικού σφάλματος. Το πορτοφολι δεν κρυπτογραφηθηκε. - - + + The supplied passphrases do not match. Οι εισαχθέντες κωδικοί δεν ταιριάζουν. - + Wallet unlock failed το ξεκλείδωμα του πορτοφολιού απέτυχε - - - + + + The passphrase entered for the wallet decryption was incorrect. Ο κωδικος που εισήχθη για την αποκρυπτογραφηση του πορτοφολιού ήταν λαθος. - + Wallet decryption failed Η αποκρυπτογραφηση του πορτοφολιού απέτυχε - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Ο κωδικος του πορτοφολιού άλλαξε με επιτυχία. BitcoinGUI - - Bitcoin Wallet - Πορτοφολι Bitcoin - - - + Sign &message... - + Υπογραφή &Μηνύματος... - - Show/Hide &Bitcoin - Εμφάνισε/Κρύψε &Bitcoin - - - + Synchronizing with network... Συγχρονισμός με το δίκτυο... - + &Overview &Επισκόπηση - + Show general overview of wallet Εμφάνισε γενική εικονα του πορτοφολιού - + &Transactions &Συναλλαγές - + Browse transaction history Περιήγηση στο ιστορικο συνναλαγων - - &Address Book - &Βιβλίο Διευθύνσεων - - - + Edit the list of stored addresses and labels Εξεργασια της λιστας των αποθηκευμενων διευθύνσεων και ετικετων - - &Receive coins - &Παραλαβή νομισματων - - - + Show the list of addresses for receiving payments Εμφάνισε την λίστα των διευθύνσεων για την παραλαβή πληρωμων - - &Send coins - &Αποστολη νομισματων - - - - Prove you control an address - Απέδειξε ότι ελέγχεις μια διεύθυνση - - - + E&xit Έ&ξοδος - + Quit application Εξοδος από την εφαρμογή - - &About %1 - &Περί %1 + + Show information about CasinoCoin + Εμφάνισε πληροφορίες σχετικά με το CasinoCoin - - Show information about Bitcoin - Εμφάνισε πληροφορίες σχετικά με το Bitcoin - - - + About &Qt Σχετικά με &Qt - + Show information about Qt Εμφάνισε πληροφορίες σχετικά με Qt - + &Options... &Επιλογές... - + &Encrypt Wallet... - + &Κρυπτογράφησε το πορτοφόλι - + &Backup Wallet... - + &Αντίγραφο ασφαλείας του πορτοφολιού - + &Change Passphrase... - - - - - ~%n block(s) remaining - ~%n μπλοκ απέμεινε~%n μπλοκ απέμειναν + &Άλλαξε κωδικο πρόσβασης - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Κατέβηκαν %1 από %2 μπλοκ του ιστορικού συναλλαγών (%3% ολοκληρώθηκαν) + + Importing blocks from disk... + Εισαγωγή μπλοκ από τον σκληρο δίσκο ... - - &Export... - &Εξαγωγή + + Reindexing blocks on disk... + Φόρτωση ευρετηρίου μπλοκ στον σκληρο δισκο... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Στείλε νομισματα σε μια διεύθυνση casinocoin - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Επεργασία ρυθμισεων επιλογών για το CasinoCoin - - Show or hide the Bitcoin window - Εμφάνισε ή κρύψε το παράθυρο Bitcoin - - - - Export the data in the current tab to a file - Εξαγωγή δεδομένων καρτέλας σε αρχείο - - - - Encrypt or decrypt wallet - Κρυπτογράφηση ή αποκρυπτογράφηση πορτοφολιού - - - + Backup wallet to another location Δημιουργία αντιγράφου ασφαλείας πορτοφολιού σε άλλη τοποθεσία - + Change the passphrase used for wallet encryption Αλλαγή του κωδικού κρυπτογράφησης του πορτοφολιού - + &Debug window - + &Παράθυρο αποσφαλμάτωσης - + Open debugging and diagnostic console - + Άνοιγμα κονσόλας αποσφαλμάτωσης και διαγνωστικών - + &Verify message... - + &Επιβεβαίωση μηνύματος - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Πορτοφόλι + + + + &Send + &Αποστολή + + + + &Receive + &Παραλαβή + + + + &Addresses + &Διεύθυνσεις + + + + &About CasinoCoin + &Σχετικα:CasinoCoin + + + + &Show / Hide + &Εμφάνισε/Κρύψε + + + + Show or hide the main Window + Εμφάνιση ή αποκρύψη του κεντρικου παράθυρου + + + + Encrypt the private keys that belong to your wallet + Κρυπτογραφήστε τα ιδιωτικά κλειδιά που ανήκουν στο πορτοφόλι σας + + + + Sign messages with your CasinoCoin addresses to prove you own them + Υπογράψτε ένα μήνυμα για να βεβαιώσετε πως είστε ο κάτοχος αυτής της διεύθυνσης + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως ανήκει μια συγκεκριμένη διεύθυνση CasinoCoin + + + &File &Αρχείο - + &Settings &Ρυθμίσεις - + &Help &Βοήθεια - + Tabs toolbar Εργαλειοθήκη καρτελών - - Actions toolbar - Εργαλειοθήκη ενεργειών - - - - + + [testnet] [testnet] - - - Bitcoin client - Πελάτης Bitcoin + + CasinoCoin client + Πελάτης CasinoCoin - - %n active connection(s) to Bitcoin network - %n ενεργή σύνδεση στο δίκτυο Bitcoin%n ενεργές συνδέσεις στο δίκτυο Βitcoin + + %n active connection(s) to CasinoCoin network + %n ενεργή σύνδεση στο δίκτυο CasinoCoin%n ενεργές συνδέσεις στο δίκτυο Βitcoin - - Downloaded %1 blocks of transaction history. + + No block source available... + Η πηγή του μπλοκ δεν ειναι διαθέσιμη... + + + + Processed %1 of %2 (estimated) blocks of transaction history. + Μεταποιημένα %1 απο % 2 (κατ 'εκτίμηση) μπλοκ της ιστορίας της συναλλαγής. + + + + Processed %1 blocks of transaction history. Έγινε λήψη %1 μπλοκ ιστορικού συναλλαγών - - %n second(s) ago - %n δευτερόλεπτο πριν%n δευτερόλεπτα πριν + + %n hour(s) + %n ώρες %n ώρες - - %n minute(s) ago - %n λεπτό πριν%n λεπτά πριν + + %n day(s) + %n ημέρες %n ημέρες - - %n hour(s) ago - %n ώρα πριν%n ώρες πριν - - - - %n day(s) ago - %n ημέρα πριν%n ημέρες πριν + + %n week(s) + %n εβδομαδες%n εβδομαδες - - Up to date - Ενημερωμένο + + %1 behind + %1 πίσω - - Catching up... - Ενημέρωση... + + Last received block was generated %1 ago. + Το τελευταίο μπλοκ που ελήφθη δημιουργήθηκε %1 πριν. - - Last received block was generated %1. - Το τελευταίο μπλοκ που ελήφθη %1. + + Transactions after this will not yet be visible. + Οι συναλλαγές μετά από αυτό δεν θα είναι ακόμη ορατες. - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + Error + Σφάλμα + + + + Warning + Προειδοποίηση + + + + Information + Πληροφορία + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Η συναλλαγή ξεπερνάει το όριο. Μπορεί να ολοκληρωθεί με μια αμοιβή των %1, η οποία αποδίδεται στους κόμβους που επεξεργάζονται τις συναλλαγές και βοηθούν στην υποστήριξη του δικτύου. Θέλετε να συνεχίσετε; - - Confirm transaction fee - + + Up to date + Ενημερωμένο - + + Catching up... + Ενημέρωση... + + + + Confirm transaction fee + Επιβεβαίωση αμοιβής συναλλαγής + + + Sent transaction Η συναλλαγή απεστάλη - + Incoming transaction Εισερχόμενη συναλλαγή - + Date: %1 Amount: %2 Type: %3 @@ -584,538 +651,485 @@ Address: %4 - + + + URI handling + Χειρισμός URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + Το URI δεν μπορεί να αναλυθεί! Αυτό μπορεί να προκληθεί από μια μη έγκυρη διεύθυνση CasinoCoin ή ακατάλληλη παραμέτρο URI. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Το πορτοφόλι είναι <b>κρυπτογραφημένο</b> και <b>ξεκλείδωτο</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Το πορτοφόλι είναι <b>κρυπτογραφημένο</b> και <b>κλειδωμένο</b> - - Backup Wallet - Αντίγραφο ασφαλείας του πορτοφολιού - - - - Wallet Data (*.dat) - Αρχεία δεδομένων πορτοφολιού (*.dat) - - - - Backup Failed - Αποτυχία κατά τη δημιουργία αντιγράφου - - - - There was an error trying to save the wallet data to the new location. - Παρουσιάστηκε σφάλμα κατά την αποθήκευση των δεδομένων πορτοφολιού στη νέα τοποθεσία. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Παρουσιάστηκε ανεπανόρθωτο σφάλμα. Το CasinoCoin δεν μπορεί πλέον να συνεχίσει με ασφάλεια και θα τερματισθει. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Απεικόνισης - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Επιλέξτε τη μονάδα υποδιαίρεσης που θα εμφανίζεται - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Ειδοποίηση Δικτύου EditAddressDialog - + Edit Address Επεξεργασία Διεύθυνσης - + &Label &Επιγραφή - + The label associated with this address book entry Η επιγραφή που σχετίζεται με αυτή την καταχώρηση του βιβλίου διευθύνσεων - + &Address &Διεύθυνση - + The address associated with this address book entry. This can only be modified for sending addresses. Η διεύθυνση που σχετίζεται με αυτή την καταχώρηση του βιβλίου διευθύνσεων. Μπορεί να τροποποιηθεί μόνο για τις διευθύνσεις αποστολής. - + New receiving address Νέα διεύθυνση λήψης - + New sending address Νέα διεύθυνση αποστολής - + Edit receiving address Επεξεργασία διεύθυνσης λήψης - + Edit sending address Επεξεργασία διεύθυνσης αποστολής - + The entered address "%1" is already in the address book. Η διεύθυνση "%1" βρίσκεται ήδη στο βιβλίο διευθύνσεων. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Η διεύθυνση "%1" δεν είναι έγκυρη CasinoCoin διεύθυνση. - + Could not unlock wallet. Δεν είναι δυνατό το ξεκλείδωμα του πορτοφολιού. - + New key generation failed. Η δημιουργία νέου κλειδιού απέτυχε. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + casinocoin-qt - + version - + έκδοση - + Usage: Χρήση: - - options - + + command-line options + επιλογής γραμμής εντολών - + UI options - + επιλογές UI - + Set language, for example "de_DE" (default: system locale) Όρισε γλώσσα, για παράδειγμα "de_DE"(προεπιλογή:τοπικές ρυθμίσεις) - + Start minimized Έναρξη ελαχιστοποιημένο - + Show splash screen on startup (default: 1) Εμφάνισε την οθόνη εκκίνησης κατά την εκκίνηση(προεπιλογή:1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - + + Options + Ρυθμίσεις - + + &Main + &Κύριο + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Η προαιρετική αμοιβή για κάθε kB επισπεύδει την επεξεργασία των συναλλαγών σας. Οι περισσότερες συναλλαγές είναι 1 kB. + + + Pay transaction &fee Αμοιβή &συναλλαγής - - Main - Βασικές + + Automatically start CasinoCoin after logging in to the system. + Αυτόματη εκκίνηση του CasinoCoin μετά την εισαγωγή στο σύστημα - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Η προαιρετική αμοιβή για κάθε kB επισπεύδει την επεξεργασία των συναλλαγών σας. Οι περισσότερες συναλλαγές είναι 1 kB. Προτείνεται αμοιβή 0.01. + + &Start CasinoCoin on system login + &Έναρξη του Βιtcoin κατά την εκκίνηση του συστήματος - - &Start Bitcoin on system login - + + Reset all client options to default. + Επαναφορα όλων των επιλογων του πελάτη σε default. - - Automatically start Bitcoin after logging in to the system - + + &Reset Options + Επαναφορα ρυθμίσεων - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + &Δίκτυο - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Μπορείτε να υπογράφετε μηνύματα με τις διευθύνσεις σας, ώστε ν' αποδεικνύετε πως αυτές σας ανήκουν. Αποφεύγετε να υπογράφετε κάτι αόριστο καθώς ενδέχεται να εξαπατηθείτε. Υπογράφετε μόνο πλήρης δηλώσεις με τις οποίες συμφωνείτε. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Αυτόματο άνοιγμα των θυρών CasinoCoin στον δρομολογητή. Λειτουργεί μόνο αν ο δρομολογητής σας υποστηρίζει τη λειτουργία UPnP. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Η διεύθυνση που θα υπογραφεί μαζί με το μήνυμα (π.χ. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Αντιγραφή διεύθυνσης από το βιβλίο διευθύνσεων - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Επικόλληση διεύθυνσης από το βιβλίο διευθύνσεων - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Εισάγετε εδώ το μήνυμα που θέλετε να υπογράψετε - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Κάντε κλικ στο "Υπογραφή Μηνύματος" για να λάβετε την υπογραφή - - - - Sign a message to prove you own this address - Υπογράψτε ένα μήνυμα για να βεβαιώσετε πως είστε ο κάτοχος αυτής της διεύθυνσης - - - - &Sign Message - &Υπογραφή Μηνύματος - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Εισάγετε μια διεύθυνση Bitcoin (π.χ. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Σφάλμα υπογραφής - - - - %1 is not a valid address. - Η %1 δεν είναι έγκυρη διεύθυνση. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Το προσωπικό κλειδί της %1 δεν είναι διαθέσιμο. - - - - Sign failed - Αποτυχία υπογραφής - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Απόδοση θυρών με χρήστη &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Αυτόματο άνοιγμα των θυρών Bitcoin στον δρομολογητή. Λειτουργεί μόνο αν ο δρομολογητής σας υποστηρίζει τη λειτουργία UPnP. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Σύνδεση στο CasinoCoin δίκτυο μέσω διαμεσολαβητή SOCKS4 (π.χ. για σύνδεση μέσω Tor) - - &Connect through SOCKS4 proxy: - &Σύνδεση μέσω SOCKS4 διαμεσολαβητή + + &Connect through SOCKS proxy: + &Σύνδεση μέσω διαμεσολαβητή SOCKS - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Σύνδεση στο Bitcoin δίκτυο μέσω διαμεσολαβητή SOCKS4 (π.χ. για σύνδεση μέσω Tor) - - - + Proxy &IP: - + &IP διαμεσολαβητή: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Διεύθυνση IP του διαμεσολαβητή (π.χ. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Η θύρα του διαμεσολαβητή (π.χ. 1234) + + &Port: + &Θύρα: - - - OptionsDialog - - Options - Ρυθμίσεις + + Port of the proxy (e.g. 9050) + Θύρα διαμεσολαβητή + + + + SOCKS &Version: + SOCKS &Έκδοση: + + + + SOCKS version of the proxy (e.g. 5) + SOCKS εκδοση του διαμεσολαβητη (e.g. 5) + + + + &Window + &Παράθυρο + + + + Show only a tray icon after minimizing the window. + Εμφάνιση μόνο εικονιδίου στην περιοχή ειδοποιήσεων κατά την ελαχιστοποίηση + + + + &Minimize to the tray instead of the taskbar + &Ελαχιστοποίηση στην περιοχή ειδοποιήσεων αντί της γραμμής εργασιών + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Ελαχιστοποίηση αντί για έξοδο κατά το κλείσιμο του παραθύρου + + + + M&inimize on close + Ε&λαχιστοποίηση κατά το κλείσιμο + + + + &Display + %Απεικόνιση + + + + User Interface &language: + Γλώσσα περιβάλλοντος εργασίας: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Εδώ μπορεί να ρυθμιστεί η γλώσσα διεπαφής χρήστη. Αυτή η ρύθμιση θα ισχύσει μετά την επανεκκίνηση του CasinoCoin. + + + + &Unit to show amounts in: + &Μονάδα μέτρησης: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Διαλέξτε την προεπιλεγμένη υποδιαίρεση που θα εμφανίζεται όταν στέλνετε νομίσματα. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Επιλέξτε αν θέλετε να εμφανίζονται οι διευθύνσεις CasinoCoin στη λίστα συναλλαγών. + + + + &Display addresses in transaction list + Εμφάνιση διευθύνσεων στη λίστα συναλλαγών + + + + &OK + &ΟΚ + + + + &Cancel + &Ακύρωση + + + + &Apply + &Εφαρμογή + + + + default + προεπιλογή + + + + Confirm options reset + Επιβεβαιώση των επιλογων επαναφοράς + + + + Some settings may require a client restart to take effect. + Για ορισμένες ρυθμίσεις πρεπει η επανεκκίνηση να τεθεί σε ισχύ. + + + + Do you want to proceed? + Θέλετε να προχωρήσετε; + + + + + Warning + Προειδοποίηση + + + + + This setting will take effect after restarting CasinoCoin. + Αυτή η ρύθμιση θα ισχύσει μετά την επανεκκίνηση του CasinoCoin. + + + + The supplied proxy address is invalid. + Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή OverviewPage - + Form Φόρμα - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Οι πληροφορίες που εμφανίζονται μπορεί να είναι ξεπερασμένες. Το πορτοφόλι σας συγχρονίζεται αυτόματα με το δίκτυο CasinoCoin μετά από μια σύνδεση, αλλά αυτή η διαδικασία δεν έχει ακόμη ολοκληρωθεί. - + Balance: Υπόλοιπο - - Number of transactions: - Αριθμός συναλλαγών - - - + Unconfirmed: Ανεπιβεβαίωτες - + Wallet - + Πορτοφόλι - + + Immature: + Ανώριμος + + + + Mined balance that has not yet matured + Εξορυγμενο υπόλοιπο που δεν έχει ακόμα ωριμάσει + + + <b>Recent transactions</b> <b>Πρόσφατες συναλλαγές</b> - + Your current balance Το τρέχον υπόλοιπο - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Το άθροισμα των συναλλαγών που δεν έχουν ακόμα επιβεβαιωθεί και δεν προσμετρώνται στο τρέχον υπόλοιπό σας - - Total number of transactions in wallet - Σύνολο συναλλαγών στο πορτοφόλι - - - - + + out of sync - + εκτός συγχρονισμού + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Δεν είναι δυνατή η εκκίνηση του CasinoCoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - - - - - QR Code Κώδικας QR - + Request Payment Αίτηση πληρωμής - + Amount: Ποσό: - - BTC - BTC - - - + Label: Επιγραφή: - + Message: Μήνυμα: - + &Save As... &Αποθήκευση ως... - + Error encoding URI into QR Code. - + Σφάλμα κατά την κωδικοποίηση του URI σε κώδικα QR - + + The entered amount is invalid, please check. + Το αναγραφόμενο ποσό δεν είναι έγκυρο, παρακαλούμε να το ελέγξετε. + + + Resulting URI too long, try to reduce the text for label / message. Το αποτέλεσμα της διεύθυνσης είναι πολύ μεγάλο. Μειώστε το μέγεθος για το κείμενο της ετικέτας/ μηνύματος. - + Save QR Code - + Αποθήκευση κώδικα QR - + PNG Images (*.png) Εικόνες PNG (*.png) @@ -1123,454 +1137,713 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Όνομα Πελάτη - - - - - - - - - + + + + + + + + + + N/A - + Μη διαθέσιμο - + Client version - + Έκδοση Πελάτη - + &Information - + &Πληροφορία - - Client - + + Using OpenSSL version + Χρησιμοποιηση της OpenSSL εκδοσης - + Startup time - + Χρόνος εκκίνησης - + Network - + Δίκτυο - + Number of connections - + Αριθμός συνδέσεων - + On testnet - + Στο testnet - + Block chain - + αλυσίδα εμποδισμού - + Current number of blocks - + Τρέχον αριθμός μπλοκ - + Estimated total blocks - + Κατ' εκτίμηση συνολικά μπλοκς - + Last block time - + Χρόνος τελευταίου μπλοκ - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Άνοιγμα - + + Command-line options + επιλογής γραμμής εντολών + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Εμφανιση του CasinoCoin-Qt μήνυματος βοήθειας για να πάρετε μια λίστα με τις πιθανές επιλογές CasinoCoin γραμμής εντολών. + + + + &Show + &Εμφάνιση + + + &Console - + &Κονσόλα - + Build date - + Ημερομηνία κατασκευής - + + CasinoCoin - Debug window + CasinoCoin - Παράθυρο αποσφαλμάτωσης + + + + CasinoCoin Core + CasinoCoin Core + + + + Debug log file + Αρχείο καταγραφής εντοπισμού σφαλμάτων + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Ανοίξτε το αρχείο καταγραφής εντοπισμού σφαλμάτων από τον τρέχοντα κατάλογο δεδομένων. Αυτό μπορεί να πάρει μερικά δευτερόλεπτα για τα μεγάλα αρχεία καταγραφής. + + + Clear console - + Καθαρισμός κονσόλας - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Καλώς ήρθατε στην CasinoCoin RPC κονσόλα. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Χρησιμοποιήστε το πάνω και κάτω βέλος για να περιηγηθείτε στο ιστορικο, και <b>Ctrl-L</b> για εκκαθαριση οθονης. - + Type <b>help</b> for an overview of available commands. - + Γράψτε <b>βοήθεια</b> για μια επισκόπηση των διαθέσιμων εντολών SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Αποστολή νομισμάτων - + Send to multiple recipients at once Αποστολή σε πολλούς αποδέκτες ταυτόχρονα - - &Add Recipient - + + Add &Recipient + &Προσθήκη αποδέκτη - + Remove all transaction fields Διαγραφή όλων των πεδίων συναλλαγής - + Clear &All - + Καθαρισμός &Όλων - + Balance: Υπόλοιπο: - + 123.456 BTC 123,456 BTC - + Confirm the send action Επιβεβαίωση αποστολής - - &Send - &Αποστολή + + S&end + Αποστολη - + <b>%1</b> to %2 (%3) <b>%1</b> σε %2 (%3) - + Confirm send coins Επιβεβαίωση αποστολής νομισμάτων - + Are you sure you want to send %1? Είστε βέβαιοι για την αποστολή %1; - + and και - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Η διεύθυνση του αποδέκτη δεν είναι σωστή. Παρακαλώ ελέγξτε ξανά. - + The amount to pay must be larger than 0. Το ποσό πληρωμής πρέπει να είναι μεγαλύτερο από 0. - + The amount exceeds your balance. - + Το ποσό ξεπερνάει το διαθέσιμο υπόλοιπο - + The total exceeds your balance when the %1 transaction fee is included. - + Το σύνολο υπερβαίνει το υπόλοιπό σας όταν συμπεριληφθεί και η αμοιβή %1 - + Duplicate address found, can only send to each address once per send operation. - + Βρέθηκε η ίδια διεύθυνση δύο φορές. Επιτρέπεται μία μόνο εγγραφή για κάθε διεύθυνση, σε κάθε διαδικασία αποστολής. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Σφάλμα: Η δημιουργία της συναλλαγής απέτυχε - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Σφάλμα: Η συναλλαγή απερρίφθη. Αυτό ενδέχεται να συμβαίνει αν κάποια από τα νομίσματα έχουν ήδη ξοδευθεί, όπως αν χρησιμοποιήσατε αντίγραφο του wallet.dat και τα νομίσματα ξοδεύθηκαν εκεί. SendCoinsEntry - + Form Φόρμα - + A&mount: &Ποσό: - + Pay &To: Πληρωμή &σε: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Διεύθυνση αποστολής της πληρωμής (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Εισάγετε μια επιγραφή για αυτή τη διεύθυνση ώστε να καταχωρηθεί στο βιβλίο διευθύνσεων - + &Label: &Επιγραφή - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Η διεύθυνση γι' αποστολή πληρωμής -(π.χ. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Επιλογή διεύθυνσης από το βιβλίο διευθύνσεων - + Alt+A Alt+A - + Paste address from clipboard Επικόλληση διεύθυνσης από το πρόχειρο - + Alt+P Alt+P - + Remove this recipient Αφαίρεση αποδέκτη - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Εισάγετε μια διεύθυνση Bitcoin (π.χ. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Εισάγετε μια διεύθυνση CasinoCoin (π.χ. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Υπογραφές - Είσοδος / Επαλήθευση μήνυματος + + + + &Sign Message + &Υπογραφή Μηνύματος + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Μπορείτε να υπογράφετε μηνύματα με τις διευθύνσεις σας, ώστε ν' αποδεικνύετε πως αυτές σας ανήκουν. Αποφεύγετε να υπογράφετε κάτι αόριστο καθώς ενδέχεται να εξαπατηθείτε. Υπογράφετε μόνο πλήρης δηλώσεις με τις οποίες συμφωνείτε. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Εισάγετε μια διεύθυνση CasinoCoin (π.χ. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Επιλογή διεύθυνσης από το βιβλίο διευθύνσεων + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Επικόλληση διεύθυνσης από το βιβλίο διευθύνσεων + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Εισάγετε εδώ το μήνυμα που θέλετε να υπογράψετε + + + + Signature + Υπογραφή + + + + Copy the current signature to the system clipboard + Αντέγραφη της επιλεγμενης διεύθυνσης στο πρόχειρο του συστηματος + + + + Sign the message to prove you own this CasinoCoin address + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως σας ανήκει μια συγκεκριμένη διεύθυνση CasinoCoin + + + + Sign &Message + Υπογραφη μήνυματος + + + + Reset all sign message fields + Επαναφορά όλων των πεδίων μήνυματος + + + + + Clear &All + Καθαρισμός &Όλων + + + + &Verify Message + &Επιβεβαίωση μηνύματος + + + + Enter the signing 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. + Πληκτρολογήστε την υπογραφή διεύθυνσης, μήνυμα (βεβαιωθείτε ότι έχετε αντιγράψει τις αλλαγές γραμμής, κενά, tabs, κ.λπ. ακριβώς) και την υπογραφή παρακάτω, για να ελέγξει το μήνυμα. Να είστε προσεκτικοί για να μην διαβάσετε περισσότερα στην υπογραφή ό, τι είναι στην υπογραφή ίδιο το μήνυμα , για να μην εξαπατηθούν από έναν άνθρωπο -in - the-middle επίθεση. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Εισάγετε μια διεύθυνση CasinoCoin (π.χ. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως υπογραφθηκε απο μια συγκεκριμένη διεύθυνση CasinoCoin + + + + Verify &Message + Επιβεβαίωση μηνύματος + + + + Reset all verify message fields + Επαναφορά όλων επαλήθευμενων πεδίων μήνυματος + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Εισάγετε μια διεύθυνση CasinoCoin (π.χ. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Κάντε κλικ στο "Υπογραφή Μηνύματος" για να λάβετε την υπογραφή + + + + Enter CasinoCoin signature + Εισαγωγή υπογραφής CasinoCoin + + + + + The entered address is invalid. + Η διεύθυνση που εισήχθη είναι λάθος. + + + + + + + Please check the address and try again. + Παρακαλούμε ελέγξτε την διεύθυνση και δοκιμάστε ξανά. + + + + + The entered address does not refer to a key. + Η διεύθυνση που έχει εισαχθεί δεν αναφέρεται σε ένα πλήκτρο. + + + + Wallet unlock was cancelled. + το ξεκλείδωμα του πορτοφολιού απέτυχε + + + + Private key for the entered address is not available. + Το προσωπικό κλειδί εισαγμενης διευθυνσης δεν είναι διαθέσιμο. + + + + Message signing failed. + Η υπογραφή του μηνύματος απέτυχε. + + + + Message signed. + Μήνυμα υπεγράφη. + + + + The signature could not be decoded. + Η υπογραφή δεν μπόρεσε να αποκρυπτογραφηθεί. + + + + + Please check the signature and try again. + Παρακαλούμε ελέγξτε την υπογραφή και δοκιμάστε ξανά. + + + + The signature did not match the message digest. + Η υπογραφή δεν ταιριάζει με το μήνυμα. + + + + Message verification failed. + Η επιβεβαίωση του μηνύματος απέτυχε + + + + Message verified. + Μήνυμα επιβεβαιώθηκε. + + + + SplashScreen + + + The CasinoCoin developers + Οι CasinoCoin προγραμματιστές + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Ανοιχτό για %1 μπλοκ - - - + Open until %1 Ανοιχτό μέχρι %1 - - %1/offline? + + %1/offline %1/χωρίς σύνδεση; - + %1/unconfirmed %1/χωρίς επιβεβαίωση - + %1 confirmations %1 επιβεβαιώσεις - - <b>Status:</b> - <b>Κατάσταση:</b> + + Status + Κατάσταση + + + + , broadcast through %n node(s) + , έχει μεταδοθεί μέσω %n κόμβων, έχει μεταδοθεί μέσω %n κόμβων - - , has not been successfully broadcast yet - , δεν έχει ακόμα μεταδοθεί μ' επιτυχία + + Date + Ημερομηνία - - , broadcast through %1 node - , έχει μεταδοθεί μέσω %1 κόμβου + + Source + Πηγή - - , broadcast through %1 nodes - , έχει μεταδοθεί μέσω %1 κόμβων + + Generated + Δημιουργία - - <b>Date:</b> - <b>Ημερομηνία:</b> + + + From + Από - - <b>Source:</b> Generated<br> - <b>Προέλευση:</b> Δημιουργία<br> + + + + To + Προς - - - <b>From:</b> - <b>Από:</b> + + + own address + δική σας διεύθυνση - - unknown - άγνωστο + + label + eπιγραφή - - - - <b>To:</b> - <b>Προς:</b> + + + + + + Credit + Πίστωση + + + + matures in %n more block(s) + ωρίμανση σε %n επιπλέον μπλοκωρίμανση σε %n επιπλέον μπλοκ - - (yours, label: - (δικές σας, επιγραφή: + + not accepted + μη αποδεκτό - - (yours) - (δικές σας) + + + + + Debit + Debit - - - - - <b>Credit:</b> - <b>Πίστωση:</b> + + Transaction fee + Τέλος συναλλαγής - - (%1 matures in %2 more blocks) - (%1 ωρίμανση σε %2 επιπλέον μπλοκ) + + Net amount + Καθαρό ποσό - - (not accepted) - (μη αποδεκτό) + + Message + Μήνυμα - - - - <b>Debit:</b> - <b>Χρέωση:</b> - - - - <b>Transaction fee:</b> - <b>Αμοιβή συναλλαγής:</b> - - - - <b>Net amount:</b> - <b>Καθαρό ποσό:</b> - - - - Message: - Μήνυμα: - - - - Comment: + + Comment Σχόλιο: - - Transaction ID: + + Transaction ID ID Συναλλαγής: - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + + Generated coins must mature 120 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. Πρέπει να περιμένετε 120 μπλοκ πριν μπορέσετε να χρησιμοποιήσετε τα νομίσματα που έχετε δημιουργήσει. Το μπλοκ που δημιουργήσατε μεταδόθηκε στο δίκτυο για να συμπεριληφθεί στην αλυσίδα των μπλοκ. Αν δεν μπει σε αυτή θα μετατραπεί σε "μη αποδεκτό" και δε θα μπορεί να καταναλωθεί. Αυτό συμβαίνει σπάνια όταν κάποιος άλλος κόμβος δημιουργήσει ένα μπλοκ λίγα δευτερόλεπτα πριν από εσάς. + + + Debug information + Πληροφορίες αποσφαλμάτωσης + + + + Transaction + Συναλλαγή + + + + Inputs + εισροές + + + + Amount + Ποσό + + + + true + αληθής + + + + false + αναληθής + + + + , has not been successfully broadcast yet + , δεν έχει ακόμα μεταδοθεί μ' επιτυχία + + + + Open for %n more block(s) + Ανοιχτό για %n μπλοκΑνοιχτό για %n μπλοκ + + + + unknown + άγνωστο + TransactionDescDialog - + Transaction details Λεπτομέρειες συναλλαγής - + This pane shows a detailed description of the transaction Αυτό το παράθυρο δείχνει μια λεπτομερή περιγραφή της συναλλαγής @@ -1578,117 +1851,117 @@ Address: %4 TransactionTableModel - + Date Ημερομηνία - + Type Τύπος - + Address Διεύθυνση - + Amount Ποσό - - Open for %n block(s) + + Open for %n more block(s) Ανοιχτό για %n μπλοκΑνοιχτό για %n μπλοκ - + Open until %1 Ανοιχτό μέχρι %1 - + Offline (%1 confirmations) Χωρίς σύνδεση (%1 επικυρώσεις) - + Unconfirmed (%1 of %2 confirmations) Χωρίς επιβεβαίωση (%1 από %2 επικυρώσεις) - + Confirmed (%1 confirmations) Επικυρωμένη (%1 επικυρώσεις) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) Το υπόλοιπο από την εξόρυξη θα είναι διαθέσιμο μετά από %n μπλοκΤο υπόλοιπο από την εξόρυξη θα είναι διαθέσιμο μετά από %n μπλοκ - + This block was not received by any other nodes and will probably not be accepted! Αυτό το μπλοκ δεν έχει παραληφθεί από κανέναν άλλο κόμβο και κατά πάσα πιθανότητα θα απορριφθεί! - + Generated but not accepted Δημιουργήθηκε αλλά απορρίφθηκε - + Received with Παραλαβή με - + Received from Ελήφθη από - + Sent to Αποστολή προς - + Payment to yourself Πληρωμή προς εσάς - + Mined Εξόρυξη - + (n/a) (δ/α) - + Transaction status. Hover over this field to show number of confirmations. Κατάσταση συναλλαγής. Πηγαίνετε το ποντίκι πάνω από αυτό το πεδίο για να δείτε τον αριθμό των επικυρώσεων - + Date and time that the transaction was received. Ημερομηνία κι ώρα λήψης της συναλλαγής. - + Type of transaction. Είδος συναλλαγής. - + Destination address of transaction. Διεύθυνση αποστολής της συναλλαγής. - + Amount removed from or added to balance. Ποσό που αφαιρέθηκε ή προστέθηκε στο υπόλοιπο. @@ -1696,826 +1969,973 @@ Address: %4 TransactionView - - + + All Όλα - + Today Σήμερα - + This week Αυτή την εβδομάδα - + This month Αυτόν τον μήνα - + Last month Τον προηγούμενο μήνα - + This year Αυτό το έτος - + Range... Έκταση... - + Received with Ελήφθη με - + Sent to Απεστάλη προς - + To yourself Προς εσάς - + Mined Εξόρυξη - + Other Άλλο - + Enter address or label to search Αναζήτηση με βάση τη διεύθυνση ή την επιγραφή - + Min amount Ελάχιστο ποσό - + Copy address Αντιγραφή διεύθυνσης - + Copy label Αντιγραφή επιγραφής - + Copy amount Αντιγραφή ποσού - + + Copy transaction ID + Αντιγραφη του ID Συναλλαγής + + + Edit label Επεξεργασία επιγραφής - + Show transaction details - + Εμφάνιση λεπτομερειών συναλλαγής - + Export Transaction Data Εξαγωγή Στοιχείων Συναλλαγών - + Comma separated file (*.csv) Αρχείο οριοθετημένο με κόμματα (*.csv) - + Confirmed Επικυρωμένες - + Date Ημερομηνία - + Type Τύπος - + Label Επιγραφή - + Address Διεύθυνση - + Amount Ποσό - + ID ID - + Error exporting Σφάλμα εξαγωγής - + Could not write to file %1. Αδυναμία εγγραφής στο αρχείο %1. - + Range: Έκταση: - + to έως - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Αντιγραφή της επιλεγμένης διεύθυνσης στο πρόχειρο - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Αποστολή... + + Send Coins + Αποστολή νομισμάτων - WindowOptionsPage + WalletView - - Window - + + &Export + &Εξαγωγή - - &Minimize to the tray instead of the taskbar - &Ελαχιστοποίηση στην περιοχή ειδοποιήσεων αντί της γραμμής εργασιών + + Export the data in the current tab to a file + Εξαγωγή δεδομένων καρτέλας σε αρχείο - - Show only a tray icon after minimizing the window - Εμφάνιση εικονιδίου στην περιοχή ειδοποιήσεων μόνο κατά την ελαχιστοποίηση + + Backup Wallet + Αντίγραφο ασφαλείας του πορτοφολιού - - M&inimize on close - + + Wallet Data (*.dat) + Αρχεία δεδομένων πορτοφολιού (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Ελαχιστοποίηση αντί για έξοδο κατά το κλείσιμο του παραθύρου + + Backup Failed + Αποτυχία κατά τη δημιουργία αντιγράφου + + + + There was an error trying to save the wallet data to the new location. + Παρουσιάστηκε σφάλμα κατά την αποθήκευση των δεδομένων πορτοφολιού στη νέα τοποθεσία. + + + + Backup Successful + Η δημιουργια αντιγραφου ασφαλειας πετυχε + + + + The wallet data was successfully saved to the new location. + Τα δεδομένα πορτοφόλιου αποθηκεύτηκαν με επιτυχία στη νέα θέση. bitcoin-core - - Bitcoin version - Έκδοση Bitcoin + + CasinoCoin version + Έκδοση CasinoCoin - + Usage: Χρήση: - - Send command to -server or bitcoind - Αποστολή εντολής στον εξυπηρετητή ή στο bitcoind + + Send command to -server or casinocoind + Αποστολή εντολής στον εξυπηρετητή ή στο casinocoind - + List commands Λίστα εντολών - + Get help for a command Επεξήγηση εντολής - + Options: Επιλογές: - - Specify configuration file (default: bitcoin.conf) - Ορίστε αρχείο ρυθμίσεων (προεπιλογή: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Ορίστε αρχείο ρυθμίσεων (προεπιλογή: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Ορίστε αρχείο pid (προεπιλογή: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Ορίστε αρχείο pid (προεπιλογή: casinocoind.pid) - - Generate coins - Δημιουργία νομισμάτων - - - - Don't generate coins - Άρνηση δημιουργίας νομισμάτων - - - + Specify data directory Ορισμός φακέλου δεδομένων - + Set database cache size in megabytes (default: 25) Όρισε το μέγεθος της βάσης προσωρινής αποθήκευσης σε megabytes(προεπιλογή:25) - - Set database disk log size in megabytes (default: 100) - Όρισε το μέγεθος της βάσης ιστορικού σε megabytes (προεπιλογή:100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Εισερχόμενες συνδέσεις στη θύρα <port> (προεπιλογή: 47950 ή στο testnet: 17950) - - Specify connection timeout (in milliseconds) - Ορισμός λήξης χρονικού ορίου (σε χιλιοστά του δευτερολέπτου) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Εισερχόμενες συνδέσεις στη θύρα <port> (προεπιλογή: 8333 ή στο testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Μέγιστες αριθμός συνδέσεων με τους peers <n> (προεπιλογή: 125) - - Connect only to the specified node - Σύνδεση μόνο με ορισμένο κόμβο - - - + Connect to a node to retrieve peer addresses, and disconnect - + Σύνδεση σε έναν κόμβο για την ανάκτηση διευθύνσεων από ομοτίμους, και αποσυνδέσh - + Specify your own public address - + Διευκρινίστε τη δικιά σας δημόσια διεύθυνση. - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Όριο αποσύνδεσης προβληματικών peers (προεπιλογή: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Δευτερόλεπτα πριν επιτραπεί ξανά η σύνδεση των προβληματικών peers (προεπιλογή: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Μέγιστος buffer λήψης ανά σύνδεση, <n>*1000 bytes (προεπιλογή: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Ένα σφάλμα συνέβη καθώς προετοιμαζόταν η πόρτα RPC %u για αναμονή IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Μέγιστος buffer αποστολής ανά σύνδεση, <n>*1000 bytes (προεπιλογή: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Εισερχόμενες συνδέσεις JSON-RPC στη θύρα <port> (προεπιλογή: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Αποδοχή εντολών κονσόλας και JSON-RPC - + Run in the background as a daemon and accept commands Εκτέλεση στο παρασκήνιο κι αποδοχή εντολών - + Use the test network Χρήση του δοκιμαστικού δικτύου - - Output extra debugging information - Έξοδος επιπλέον πληροφοριών εντοπισμού σφαλμάτων + + Accept connections from outside (default: 1 if no -proxy or -connect) + Να δέχεσαι συνδέσεις από έξω(προεπιλογή:1) - - Prepend debug output with timestamp - Χρονοσφραγίδα πληροφοριών εντοπισμού σφαλμάτων + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + - - Send trace/debug info to console instead of debug.log file - Αποστολή πληροφοριών εντοπισμού σφαλμάτων στην κονσόλα αντί του αρχείου debug.log + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Ένα σφάλμα συνέβη καθώς προετοιμαζόταν η υποδοχη RPC %u για αναμονη του IPv6, επεσε πισω στο IPv4:%s - - Send trace/debug info to debugger - Αποστολή πληροφοριών εντοπισμού σφαλμάτων στον debugger + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Αποθηκευση σε συγκεκριμένη διεύθυνση. Χρησιμοποιήστε τα πλήκτρα [Host] : συμβολισμός θύρα για IPv6 - - Username for JSON-RPC connections - Όνομα χρήστη για τις συνδέσεις JSON-RPC + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Αδυναμία κλειδώματος του φακέλου δεδομένων %s. Πιθανώς το CasinoCoin να είναι ήδη ενεργό. - - Password for JSON-RPC connections - Κωδικός για τις συνδέσεις JSON-RPC - - - - Listen for JSON-RPC connections on <port> (default: 8332) - Εισερχόμενες συνδέσεις JSON-RPC στη θύρα <port> (προεπιλογή: 8332) - - - - Allow JSON-RPC connections from specified IP address - Αποδοχή συνδέσεων JSON-RPC από συγκεκριμένη διεύθυνση IP - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Αποστολή εντολών στον κόμβο <ip> (προεπιλογή: 127.0.0.1) - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) - - - - Upgrade wallet to latest format - Αναβάθμισε το πορτοφόλι στην τελευταία έκδοση - - - - Set key pool size to <n> (default: 100) - Όριο πλήθους κλειδιών pool <n> (προεπιλογή: 100) - - - - Rescan the block chain for missing wallet transactions - Επανέλεγχος της αλυσίδας μπλοκ για απούσες συναλλαγές - - - - How many blocks to check at startup (default: 2500, 0 = all) - Πόσα μπλοκ να ελέγχω κατά την εκκίνηση (προεπιλογή:2500,0=όλα) - - - - How thorough the block verification is (0-6, default: 1) - Πόσο εξονυχιστική να είναι η επιβεβαίωση του μπλοκ(0-6, προεπιλογή:1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Ρυθμίσεις SSL: (ανατρέξτε στο Bitcoin Wiki για οδηγίες ρυθμίσεων SSL) - - - - Use OpenSSL (https) for JSON-RPC connections - Χρήση του OpenSSL (https) για συνδέσεις JSON-RPC - - - - Server certificate file (default: server.cert) - Αρχείο πιστοποιητικού του διακομιστή (προεπιλογή: server.cert) - - - - Server private key (default: server.pem) - Προσωπικό κλειδί του διακομιστή (προεπιλογή: server.pem) - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Αποδεκτά κρυπτογραφήματα (προεπιλογή: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - - - - - This help message - Αυτό το κείμενο βοήθειας - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Αδυναμία κλειδώματος του φακέλου δεδομένων %s. Πιθανώς το Bitcoin να είναι ήδη ενεργό. - - - - Bitcoin - Bitcoin - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - Φόρτωση διευθύνσεων... - - - - Error loading blkindex.dat - Σφάλμα φόρτωσης blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - Σφάλμα φόρτωσης wallet.dat: Κατεστραμμένο Πορτοφόλι - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Σφάλμα φόρτωσης wallet.dat: Το Πορτοφόλι απαιτεί μια νεότερη έκδοση του Bitcoin - - - - Wallet needed to be rewritten: restart Bitcoin to complete - Απαιτείται η επανεγγραφή του Πορτοφολιού, η οποία θα ολοκληρωθεί στην επανεκκίνηση του Bitcoin - - - - Error loading wallet.dat - Σφάλμα φόρτωσης αρχείου wallet.dat - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Σφάλμα: το πορτοφόλι είναι κλειδωμένο, δεν μπορεί να δημιουργηθεί συναλλαγή - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Σφάλμα: Αυτή η συναλλαγή απαιτεί αμοιβή συναλλαγής τουλάχιστον %s λόγω του μεγέθους, πολυπλοκότητας ή της χρήσης πρόσφατης παραλαβής κεφαλαίου - - - - Error: Transaction creation failed - Σφάλμα: Η δημιουργία της συναλλαγής απέτυχε - - - - Sending... - Αποστολή... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. Σφάλμα: Η συναλλαγή απορρίφθηκε. Αυτό ίσως οφείλεται στο ότι τα νομίσματά σας έχουν ήδη ξοδευτεί, π.χ. με την αντιγραφή του wallet.dat σε άλλο σύστημα και την χρήση τους εκεί, χωρίς η συναλλαγή να έχει καταγραφεί στο παρόν σύστημα. - + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Σφάλμα: Αυτή η συναλλαγή απαιτεί αμοιβή συναλλαγής τουλάχιστον %s λόγω του μεγέθους, πολυπλοκότητας ή της χρήσης πρόσφατης παραλαβής κεφαλαίου + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Εκτέλεση της εντολής όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Ορίστε το μέγιστο μέγεθος των high-priority/low-fee συναλλαγων σε bytes (προεπιλογή: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Αυτό είναι ένα προ-τεστ κυκλοφορίας - χρησιμοποιήστε το με δική σας ευθύνη - δεν χρησιμοποιείτε για εξόρυξη ή για αλλες εφαρμογές + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Προειδοποίηση: Η παράμετρος -paytxfee είναι πολύ υψηλή. Πρόκειται για την αμοιβή που θα πληρώνετε για κάθε συναλλαγή που θα στέλνετε. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Προειδοποίηση: Εμφανίσεις συναλλαγων δεν μπορεί να είναι σωστες! Μπορεί να χρειαστεί να αναβαθμίσετε, ή άλλοι κόμβοι μπορεί να χρειαστεί να αναβαθμίστουν. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Προειδοποίηση: Παρακαλώ βεβαιωθείτε πως η ημερομηνία κι ώρα του συστήματός σας είναι σωστές. Αν το ρολόι του υπολογιστή σας πάει λάθος, ενδέχεται να μη λειτουργεί σωστά το CasinoCoin. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Προειδοποίηση : Σφάλμα wallet.dat κατα την ανάγνωση ! Όλα τα κλειδιά αναγνωρισθηκαν σωστά, αλλά τα δεδομένα των συναλλαγών ή καταχωρήσεις στο βιβλίο διευθύνσεων μπορεί να είναι ελλιπείς ή λανθασμένα. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Προειδοποίηση : το αρχειο wallet.dat ειναι διεφθαρμένο, τα δεδομένα σώζονται ! Original wallet.dat αποθηκεύονται ως πορτοφόλι { timestamp } bak στο % s ? . . Αν το υπόλοιπο του ή τις συναλλαγές σας, είναι λάθος θα πρέπει να επαναφέρετε από ένα αντίγραφο ασφαλείας + + + + Attempt to recover private keys from a corrupt wallet.dat + Προσπάθεια για ανακτησει ιδιωτικων κλειδιων από ενα διεφθαρμένο αρχειο wallet.dat + + + + Block creation options: + Αποκλεισμός επιλογων δημιουργίας: + + + + Connect only to the specified node(s) + Σύνδεση μόνο με ορισμένους κόμβους + + + + Corrupted block database detected + Εντοπισθηκε διεφθαρμενη βαση δεδομενων των μπλοκ + + + + Discover own IP address (default: 1 when listening and no -externalip) + Ανακαλύψτε την δικη σας IP διεύθυνση (προεπιλογή: 1 όταν ακούει και δεν - externalip) + + + + Do you want to rebuild the block database now? + Θελετε να δημιουργηθει τωρα η βαση δεδομενων του μπλοκ? + + + + Error initializing block database + Σφάλμα κατά την ενεργοποίηση της βάσης δεδομένων μπλοκ + + + + Error initializing wallet database environment %s! + Σφάλμα κατά την ενεργοποίηση της βάσης δεδομένων πορτοφόλιου %s! + + + + Error loading block database + Σφάλμα φορτωσης της βασης δεδομενων των μπλοκ + + + + Error opening block database + Σφάλμα φορτωσης της βασης δεδομενων των μπλοκ + + + + Error: Disk space is low! + Προειδοποίηση: Χαμηλός χώρος στο δίσκο + + + + Error: Wallet locked, unable to create transaction! + Σφάλμα: το πορτοφόλι είναι κλειδωμένο, δεν μπορεί να δημιουργηθεί συναλλαγή + + + + Error: system error: + Λάθος: λάθος συστήματος: + + + + Failed to listen on any port. Use -listen=0 if you want this. + ταλαιπωρηθειτε για να ακούσετε σε οποιαδήποτε θύρα. Χρήση - ακούστε = 0 , αν θέλετε αυτό. + + + + Failed to read block info + Αποτυχία αναγνωσης των block πληροφοριων + + + + Failed to read block + Η αναγνωση του μπλοκ απετυχε + + + + Failed to sync block index + Ο συγχρονισμος του μπλοκ ευρετηριου απετυχε + + + + Failed to write block index + Η δημιουργια του μπλοκ ευρετηριου απετυχε + + + + Failed to write block info + Η δημιουργια των μπλοκ πληροφοριων απετυχε + + + + Failed to write block + Η δημιουργια του μπλοκ απετυχε + + + + Failed to write file info + Αδυναμία εγγραφής πληροφοριων αρχειου + + + + Failed to write to coin database + Αποτυχία εγγραφής στη βάση δεδομένων νομίσματος + + + + Failed to write transaction index + Αποτυχία εγγραφής δείκτη συναλλαγών + + + + Failed to write undo data + Αποτυχία εγγραφής αναίρεσης δεδομένων + + + + Find peers using DNS lookup (default: 1 unless -connect) + Βρες ομότιμους υπολογιστές χρησιμοποιώντας αναζήτηση DNS(προεπιλογή:1) + + + + Generate coins (default: 0) + Δημιουργία νομισμάτων (προκαθορισμος: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Πόσα μπλοκ να ελέγχθουν κατά την εκκίνηση (προεπιλογή:288,0=όλα) + + + + How thorough the block verification is (0-4, default: 3) + Πόσο εξονυχιστική να είναι η επιβεβαίωση του μπλοκ(0-4, προεπιλογή:3) + + + + Not enough file descriptors available. + Δεν ειναι αρκετες περιγραφες αρχείων διαθέσιμες. + + + + Rebuild block chain index from current blk000??.dat files + Εισαγωγή μπλοκ από εξωτερικό αρχείο blk000?.dat + + + + Set the number of threads to service RPC calls (default: 4) + Ορίσμος του αριθμόυ θεματων στην υπηρεσία κλήσεων RPC (προεπιλογή: 4) + + + + Verifying blocks... + Επαλήθευση των μπλοκ... + + + + Verifying wallet... + Επαλήθευση πορτοφολιου... + + + + Imports blocks from external blk000??.dat file + Εισαγωγή μπλοκ από εξωτερικό αρχείο blk000?.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Ορίσμος του αριθμό των νημάτων ελέγχου σεναρίου (μέχρι 16, 0 = auto, <0 = αφήνουν τους πολλους πυρήνες δωρεάν, default: 0) + + + + Information + Πληροφορία + + + + Invalid -tor address: '%s' + Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' + + + + Maintain a full transaction index (default: 0) + Διατηρήση ένος πλήρες ευρετήριου συναλλαγών (προεπιλογή: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Μέγιστος buffer λήψης ανά σύνδεση, <n>*1000 bytes (προεπιλογή: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Μέγιστος buffer αποστολής ανά σύνδεση, <n>*1000 bytes (προεπιλογή: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Μονο αποδοχη αλυσίδας μπλοκ που ταιριάζει με τα ενσωματωμένα σημεία ελέγχου (προεπιλογή: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Συνδέση μόνο σε κόμβους του δικτύου <net> (IPv4, IPv6 ή Tor) + + + + Output extra debugging information. Implies all other -debug* options + Έξοδος επιπλέον πληροφοριών εντοπισμού σφαλμάτων + + + + Output extra network debugging information + Έξοδος επιπλέον πληροφοριών εντοπισμού σφαλμάτων + + + + Prepend debug output with timestamp + Χρονοσφραγίδα πληροφοριών εντοπισμού σφαλμάτων + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Ρυθμίσεις SSL: (ανατρέξτε στο CasinoCoin Wiki για οδηγίες ρυθμίσεων SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Επιλέξτε την έκδοση του διαμεσολαβητη για να χρησιμοποιήσετε (4-5 , προεπιλογή: 5) + + + + Send trace/debug info to console instead of debug.log file + Αποστολή πληροφοριών εντοπισμού σφαλμάτων στην κονσόλα αντί του αρχείου debug.log + + + + Send trace/debug info to debugger + Αποστολή πληροφοριών εντοπισμού σφαλμάτων στον debugger + + + + Set maximum block size in bytes (default: 250000) + Ορίσμος του μέγιστου μέγεθος block σε bytes (προεπιλογή: 250000) + + + + Set minimum block size in bytes (default: 0) + Ορίστε το μέγιστο μέγεθος block σε bytes (προεπιλογή: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Συρρίκνωση του αρχείο debug.log κατα την εκκίνηση του πελάτη (προεπιλογή: 1 όταν δεν-debug) + + + + Signing transaction failed + Η υπογραφή συναλλαγής απέτυχε + + + + Specify connection timeout in milliseconds (default: 5000) + Ορισμός λήξης χρονικού ορίου σε χιλιοστά του δευτερολέπτου(προεπιλογή:5000) + + + + System error: + Λάθος Συστήματος: + + + + Transaction amount too small + Το ποσό της συναλλαγής είναι πολύ μικρο + + + + Transaction amounts must be positive + Τα ποσά των συναλλαγών πρέπει να είναι θετικα + + + + Transaction too large + Η συναλλαγή ειναι πολύ μεγάλη + + + + Use UPnP to map the listening port (default: 0) + Χρησιμοποίηση του UPnP για την χρήση της πόρτας αναμονής (προεπιλογή:0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Χρησιμοποίηση του UPnP για την χρήση της πόρτας αναμονής (προεπιλογή:1) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Χρήση διακομιστή μεσολάβησης για την επίτευξη των Tor κρυμμένων υπηρεσιων (προεπιλογή: ίδιο με το-proxy) + + + + Username for JSON-RPC connections + Όνομα χρήστη για τις συνδέσεις JSON-RPC + + + + Warning + Προειδοποίηση + + + + Warning: This version is obsolete, upgrade required! + Προειδοποίηση: Αυτή η έκδοση είναι ξεπερασμένη, απαιτείται αναβάθμιση + + + + You need to rebuild the databases using -reindex to change -txindex + Θα πρέπει να ξαναχτίστουν οι βάσεις δεδομένων που χρησιμοποιούντε-Αναδημιουργία αλλάγων-txindex + + + + wallet.dat corrupt, salvage failed + Το αρχειο wallet.dat ειναι διεφθαρμένο, η διάσωση απέτυχε + + + + Password for JSON-RPC connections + Κωδικός για τις συνδέσεις JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Αποδοχή συνδέσεων JSON-RPC από συγκεκριμένη διεύθυνση IP + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Αποστολή εντολών στον κόμβο <ip> (προεπιλογή: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) + + + + Upgrade wallet to latest format + Αναβάθμισε το πορτοφόλι στην τελευταία έκδοση + + + + Set key pool size to <n> (default: 100) + Όριο πλήθους κλειδιών pool <n> (προεπιλογή: 100) + + + + Rescan the block chain for missing wallet transactions + Επανέλεγχος της αλυσίδας μπλοκ για απούσες συναλλαγές + + + + Use OpenSSL (https) for JSON-RPC connections + Χρήση του OpenSSL (https) για συνδέσεις JSON-RPC + + + + Server certificate file (default: server.cert) + Αρχείο πιστοποιητικού του διακομιστή (προεπιλογή: server.cert) + + + + Server private key (default: server.pem) + Προσωπικό κλειδί του διακομιστή (προεπιλογή: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Αποδεκτά κρυπτογραφήματα (προεπιλογή: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Αυτό το κείμενο βοήθειας + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Αδύνατη η σύνδεση με τη θύρα %s αυτού του υπολογιστή (bind returned error %d, %s) + + + + Connect through socks proxy + Σύνδεση μέσω διαμεσολαβητή socks + + + + Allow DNS lookups for -addnode, -seednode and -connect + Να επιτρέπονται οι έλεγχοι DNS για προσθήκη και σύνδεση κόμβων + + + + Loading addresses... + Φόρτωση διευθύνσεων... + + + + Error loading wallet.dat: Wallet corrupted + Σφάλμα φόρτωσης wallet.dat: Κατεστραμμένο Πορτοφόλι + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Σφάλμα φόρτωσης wallet.dat: Το Πορτοφόλι απαιτεί μια νεότερη έκδοση του CasinoCoin + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Απαιτείται η επανεγγραφή του Πορτοφολιού, η οποία θα ολοκληρωθεί στην επανεκκίνηση του CasinoCoin + + + + Error loading wallet.dat + Σφάλμα φόρτωσης αρχείου wallet.dat + + + + Invalid -proxy address: '%s' + Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή: '%s' + + + + Unknown network specified in -onlynet: '%s' + Άγνωστo δίκτυο ορίζεται σε onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + Άγνωστo δίκτυο ορίζεται: %i + + + + Cannot resolve -bind address: '%s' + Δεν μπορώ να γράψω την προεπιλεγμένη διεύθυνση: '%s' + + + + Cannot resolve -externalip address: '%s' + Δεν μπορώ να γράψω την προεπιλεγμένη διεύθυνση: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' + + + Invalid amount Λάθος ποσότητα - + Insufficient funds Ανεπαρκές κεφάλαιο - + Loading block index... Φόρτωση ευρετηρίου μπλοκ... - + Add a node to connect to and attempt to keep the connection open Προσέθεσε ένα κόμβο για σύνδεση και προσπάθησε να κρατήσεις την σύνδεση ανοιχτή - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Αδύνατη η σύνδεση με τη θύρα %s αυτού του υπολογιστή. Το CasinoCoin είναι πιθανώς ήδη ενεργό. - - Find peers using internet relay chat (default: 0) - Βρες ομότιμους υπολογιστές χρησιμοποιώντας internet relay chat(Προεπιλογή:0) - - - - Accept connections from outside (default: 1) - Να δέχεσαι συνδέσεις από έξω(προεπιλογή:1) - - - - Find peers using DNS lookup (default: 1) - Βρες ομότιμους υπολογιστές χρησιμοποιώντας αναζήτηση DNS(προεπιλογή:1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Χρησιμοποίησε Universal Plug and Play για την χρήση της πόρτας αναμονής (προεπιλογή:1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Χρησιμοποίησε Universal Plug and Play για την χρήση της πόρτας αναμονής (προεπιλογή:0) - - - + Fee per KB to add to transactions you send Αμοιβή ανά KB που θα προστίθεται στις συναλλαγές που στέλνεις - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Φόρτωση πορτοφολιού... - + Cannot downgrade wallet Δεν μπορώ να υποβαθμίσω το πορτοφόλι - - Cannot initialize keypool - Δεν μπορώ αν αρχικοποιήσω την λίστα κλειδιών - - - + Cannot write default address Δεν μπορώ να γράψω την προεπιλεγμένη διεύθυνση - + Rescanning... Ανίχνευση... - + Done loading Η φόρτωση ολοκληρώθηκε - + To use the %s option Χρήση της %s επιλογής - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, πρέπει να βάλεις ένα κωδικό στο αρχείο παραμέτρων: %s -Προτείνεται να χρησιμοποιήσεις τον παρακάτω τυχαίο κωδικό: -rpcuser=bitcoinrpc -rpcpassword=%s -(δεν χρειάζεται να θυμάσαι αυτόν τον κωδικό) -Εάν το αρχείο δεν υπάρχει, δημιούργησε το με δικαιώματα μόνο για ανάγνωση από τον δημιουργό. - - - + Error Σφάλμα - - An error occured while setting up the RPC port %i for listening: %s - Ένα σφάλμα συνέβη καθώς προετοιμαζόταν η πόρτα RPC %i για αναμονή:%s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. Πρέπει να βάλεις ένα κωδικό στο αρχείο παραμέτρων: %s Εάν το αρχείο δεν υπάρχει, δημιούργησε το με δικαιώματα μόνο για ανάγνωση από τον δημιουργό - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Προειδοποίηση: Παρακαλώ βεβαιωθείτε πως η ημερομηνία κι ώρα του συστήματός σας είναι σωστές. Αν το ρολόι του υπολογιστή σας πάει λάθος, ενδέχεται να μη λειτουργεί σωστά το Bitcoin. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index bb806b8..03010c3 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -5,1287 +5,1702 @@ AboutDialog - About Bitcoin - + + About CasinoCoin + About CasinoCoin - <b>Bitcoin</b> version - + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> version - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers + The CasinoCoin developers AddressBookPage + Address Book - + Address Book + Double-click to edit address or label - + Double-click to edit address or label + Create a new address - + Create a new address + Copy the currently selected address to the system clipboard - + Copy the currently selected address to the system clipboard + &New Address - + &New Address - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + &Copy Address - + &Copy Address + Show &QR Code - + Show &QR Code - Sign a message to prove you own a Bitcoin address - + + Sign a message to prove you own a CasinoCoin address + Sign a message to prove you own a CasinoCoin address - &Sign Message - + + Sign &Message + Sign &Message - Verify a message to ensure it was signed with a specified Bitcoin address - + + Delete the currently selected address from the list + Delete the currently selected address from the list + + Export the data in the current tab to a file + Export the data in the current tab to a file + + + + &Export + &Export + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verify a message to ensure it was signed with a specified CasinoCoin address + + + &Verify Message - - - - Delete the currently selected address from the list. Only sending addresses can be deleted. - + &Verify Message + &Delete - + &Delete + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + Copy &Label - + Copy &Label + &Edit - + &Edit + + Send &Coins + Send &Coins + + + Export Address Book Data - + Export Address Book Data + Comma separated file (*.csv) - + Comma separated file (*.csv) + Error exporting - + Error exporting + Could not write to file %1. - + Could not write to file %1. AddressTableModel + Label - + Label + Address - + Address + (no label) - + (no label) AskPassphraseDialog + Passphrase Dialog - + Passphrase Dialog + Enter passphrase - + Enter passphrase + New passphrase - + New passphrase + Repeat new passphrase - + Repeat new passphrase + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Encrypt wallet - + Encrypt wallet + This operation needs your wallet passphrase to unlock the wallet. - + This operation needs your wallet passphrase to unlock the wallet. + Unlock wallet - + Unlock wallet + This operation needs your wallet passphrase to decrypt the wallet. - + This operation needs your wallet passphrase to decrypt the wallet. + Decrypt wallet - + Decrypt wallet + Change passphrase - + Change passphrase + Enter the old and new passphrase to the wallet. - + Enter the old and new passphrase to the wallet. + Confirm wallet encryption - + Confirm wallet encryption - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + Are you sure you wish to encrypt your wallet? + Are you sure you wish to encrypt your wallet? + + + + 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. + 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. + + + + + Warning: The Caps Lock key is on! + Warning: The Caps Lock key is on! + + + + Wallet encrypted - + Wallet encrypted - Bitcoin 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. - - - - Warning: The Caps Lock key is on. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + Wallet encryption failed - + Wallet encryption failed + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + The supplied passphrases do not match. - + The supplied passphrases do not match. + Wallet unlock failed - + Wallet unlock failed + + + The passphrase entered for the wallet decryption was incorrect. - + The passphrase entered for the wallet decryption was incorrect. + Wallet decryption failed - + Wallet decryption failed + Wallet passphrase was successfully changed. - + Wallet passphrase was successfully changed. BitcoinGUI - Bitcoin Wallet - - - + Sign &message... - - - - Show/Hide &Bitcoin - + Sign &message... + Synchronizing with network... - + Synchronizing with network... + &Overview - + &Overview + Show general overview of wallet - + Show general overview of wallet + &Transactions - + &Transactions + Browse transaction history - - - - &Address Book - + Browse transaction history + Edit the list of stored addresses and labels - - - - &Receive coins - + Edit the list of stored addresses and labels + Show the list of addresses for receiving payments - - - - &Send coins - + Show the list of addresses for receiving payments + E&xit - + E&xit + Quit application - + Quit application - &About %1 - - - - Show information about Bitcoin - + + Show information about CasinoCoin + Show information about CasinoCoin + About &Qt - + About &Qt + Show information about Qt - + Show information about Qt + &Options... - + &Options... + &Encrypt Wallet... - + &Encrypt Wallet... + &Backup Wallet... - + &Backup Wallet... + &Change Passphrase... - - - - ~%n block(s) remaining - - ~%n block remaining - ~%n blocks remaining - + &Change Passphrase... - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Importing blocks from disk... - &Export... - + + Reindexing blocks on disk... + Reindexing blocks on disk... - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Send coins to a CasinoCoin address - Sign a message to prove you own a Bitcoin address - - - - Verify a message to ensure it was signed with a specified Bitcoin address - - - - S&ignatures - - - - Modify configuration options for Bitcoin - - - - Show or hide the Bitcoin window - - - - Export the data in the current tab to a file - - - - Encrypt or decrypt wallet - + + Modify configuration options for CasinoCoin + Modify configuration options for CasinoCoin + Backup wallet to another location - + Backup wallet to another location + Change the passphrase used for wallet encryption - + Change the passphrase used for wallet encryption + &Debug window - + &Debug window + Open debugging and diagnostic console - + Open debugging and diagnostic console + &Verify message... - + &Verify message... + + + CasinoCoin + CasinoCoin + + + + Wallet + Wallet + + + + &Send + &Send + + + + &Receive + &Receive + + + + &Addresses + &Addresses + + + + &About CasinoCoin + &About CasinoCoin + + + + &Show / Hide + &Show / Hide + + + + Show or hide the main Window + Show or hide the main Window + + + + Encrypt the private keys that belong to your wallet + Encrypt the private keys that belong to your wallet + + + + Sign messages with your CasinoCoin addresses to prove you own them + Sign messages with your CasinoCoin addresses to prove you own them + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + &File - + &File + &Settings - + &Settings + &Help - + &Help + Tabs toolbar - - - - Actions toolbar - + Tabs toolbar + + [testnet] - + [testnet] - Bitcoin client - + + CasinoCoin client + CasinoCoin client - %n active connection(s) to Bitcoin network + + %n active connection(s) to CasinoCoin network - %n active connection to Bitcoin network - %n active connections to Bitcoin network + %n active connection to CasinoCoin network + %n active connections to CasinoCoin network - Downloaded %1 blocks of transaction history. - + + No block source available... + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. + Processed %1 of %2 (estimated) blocks of transaction history. + + + + Processed %1 blocks of transaction history. + Processed %1 blocks of transaction history. - %n second(s) ago + + %n hour(s) - %n second ago - %n seconds ago + %n hour + %n hours - %n minute(s) ago + + %n day(s) - %n minute ago - %n minutes ago + %n day + %n days - %n hour(s) ago + + %n week(s) - %n hour ago - %n hours ago - - - - %n day(s) ago - - %n day ago - %n days ago + %n week + %n weeks + + %1 behind + %1 behind + + + + Last received block was generated %1 ago. + Last received block was generated %1 ago. + + + + Transactions after this will not yet be visible. + Transactions after this will not yet be visible. + + + + Error + Error + + + + Warning + Warning + + + + Information + Information + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + Up to date - + Up to date + Catching up... - - - - Last received block was generated %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Catching up... + Confirm transaction fee - + Confirm transaction fee + Sent transaction - + Sent transaction + Incoming transaction - + Incoming transaction + Date: %1 Amount: %2 Type: %3 Address: %4 - + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + URI handling - + URI handling - URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. - + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Wallet is <b>encrypted</b> and currently <b>locked</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> - Backup Wallet - - - - Wallet Data (*.dat) - - - - Backup Failed - - - - There was an error trying to save the wallet data to the new location. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel + Network Alert - + Network Alert EditAddressDialog + Edit Address - + Edit Address + &Label - + &Label + The label associated with this address book entry - + The label associated with this address book entry + &Address - + &Address + The address associated with this address book entry. This can only be modified for sending addresses. - + The address associated with this address book entry. This can only be modified for sending addresses. + New receiving address - + New receiving address + New sending address - + New sending address + Edit receiving address - + Edit receiving address + Edit sending address - + Edit sending address + The entered address "%1" is already in the address book. - + The entered address "%1" is already in the address book. - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + The entered address "%1" is not a valid CasinoCoin address. + Could not unlock wallet. - + Could not unlock wallet. + New key generation failed. - + New key generation failed. GUIUtil::HelpMessageBox - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt + version - + version + Usage: - + Usage: + command-line options - + command-line options + UI options - + UI options + Set language, for example "de_DE" (default: system locale) - + Set language, for example "de_DE" (default: system locale) + Start minimized - + Start minimized + Show splash screen on startup (default: 1) - + Show splash screen on startup (default: 1) OptionsDialog + Options - + Options + &Main - + &Main - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Pay transaction &fee - + Pay transaction &fee - Automatically start Bitcoin after logging in to the system. - + + Automatically start CasinoCoin after logging in to the system. + Automatically start CasinoCoin after logging in to the system. - &Start Bitcoin on system login - + + &Start CasinoCoin on system login + &Start CasinoCoin on system login - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - + + Reset all client options to default. + Reset all client options to default. - &Detach databases at shutdown - + + &Reset Options + &Reset Options + &Network - + &Network - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Map port using &UPnP - + Map port using &UPnP - Connect to the Bitcoin network through a SOCKS proxy (e.g. when connecting through Tor). - + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + &Connect through SOCKS proxy: - + &Connect through SOCKS proxy: + Proxy &IP: - + Proxy &IP: + IP address of the proxy (e.g. 127.0.0.1) - + IP address of the proxy (e.g. 127.0.0.1) + &Port: - + &Port: + Port of the proxy (e.g. 9050) - + Port of the proxy (e.g. 9050) + SOCKS &Version: - + SOCKS &Version: + SOCKS version of the proxy (e.g. 5) - + SOCKS version of the proxy (e.g. 5) + &Window - + &Window + Show only a tray icon after minimizing the window. - + Show only a tray icon after minimizing the window. + &Minimize to the tray instead of the taskbar - + &Minimize to the tray instead of the taskbar + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + M&inimize on close - + M&inimize on close + &Display - + &Display + User Interface &language: - + User Interface &language: - The user interface language can be set here. This setting will take effect after restarting Bitcoin. - + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + &Unit to show amounts in: - + &Unit to show amounts in: + Choose the default subdivision unit to show in the interface and when sending coins. - + Choose the default subdivision unit to show in the interface and when sending coins. - Whether to show Bitcoin addresses in the transaction list or not. - + + Whether to show CasinoCoin addresses in the transaction list or not. + Whether to show CasinoCoin addresses in the transaction list or not. + &Display addresses in transaction list - + &Display addresses in transaction list + &OK - + &OK + &Cancel - + &Cancel + &Apply - + &Apply + default - + default + + Confirm options reset + Confirm options reset + + + + Some settings may require a client restart to take effect. + Some settings may require a client restart to take effect. + + + + Do you want to proceed? + Do you want to proceed? + + + + Warning - + Warning - This setting will take effect after restarting Bitcoin. - + + + This setting will take effect after restarting CasinoCoin. + This setting will take effect after restarting CasinoCoin. + The supplied proxy address is invalid. - + The supplied proxy address is invalid. OverviewPage + Form - + Form - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Balance: - - - - Number of transactions: - + Balance: + Unconfirmed: - + Unconfirmed: + Wallet - + Wallet + Immature: - + Immature: + Mined balance that has not yet matured - + Mined balance that has not yet matured + <b>Recent transactions</b> - + <b>Recent transactions</b> + Your current balance - + Your current balance + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - - - - Total number of transactions in wallet - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + out of sync - + out of sync + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Cannot start casinocoin: click-to-pay handler QRCodeDialog + QR Code Dialog - + QR Code Dialog + Request Payment - + Request Payment + Amount: - + Amount: + Label: - + Label: + Message: - + Message: + &Save As... - + &Save As... + Error encoding URI into QR Code. - + Error encoding URI into QR Code. + The entered amount is invalid, please check. - + The entered amount is invalid, please check. + Resulting URI too long, try to reduce the text for label / message. - + Resulting URI too long, try to reduce the text for label / message. + Save QR Code - + Save QR Code + PNG Images (*.png) - + PNG Images (*.png) RPCConsole - Bitcoin debug window - - - + Client name - + Client name + + + + + + + + + + N/A - + N/A + Client version - + Client version + &Information - - - - Client - + &Information + Using OpenSSL version - + Using OpenSSL version + Startup time - + Startup time + Network - + Network + Number of connections - + Number of connections + On testnet - + On testnet + Block chain - + Block chain + Current number of blocks - + Current number of blocks + Estimated total blocks - + Estimated total blocks + Last block time - - - - Debug logfile - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - + Last block time + &Open - + &Open + Command-line options - + Command-line options - Show the Bitcoin-Qt help message to get a list with possible Bitcoin command-line options. - + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + &Show - + &Show + &Console - + &Console + Build date - + Build date + + CasinoCoin - Debug window + CasinoCoin - Debug window + + + + CasinoCoin Core + CasinoCoin Core + + + + Debug log file + Debug log file + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + Clear console - + Clear console - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Welcome to the CasinoCoin RPC console. + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Type <b>help</b> for an overview of available commands. - + Type <b>help</b> for an overview of available commands. SendCoinsDialog + + + + + + + + Send Coins - + Send Coins + Send to multiple recipients at once - + Send to multiple recipients at once - &Add Recipient - + + Add &Recipient + Add &Recipient + Remove all transaction fields - + Remove all transaction fields + Clear &All - + Clear &All + Balance: - + Balance: + 123.456 BTC - + 123.456 BTC + Confirm the send action - + Confirm the send action - &Send - + + S&end + S&end + <b>%1</b> to %2 (%3) - + <b>%1</b> to %2 (%3) + Confirm send coins - + Confirm send coins + Are you sure you want to send %1? - + Are you sure you want to send %1? + and - + and - The recepient address is not valid, please recheck. - + + The recipient address is not valid, please recheck. + The recipient address is not valid, please recheck. + The amount to pay must be larger than 0. - + The amount to pay must be larger than 0. + The amount exceeds your balance. - + The amount exceeds your balance. + The total exceeds your balance when the %1 transaction fee is included. - + The total exceeds your balance when the %1 transaction fee is included. + Duplicate address found, can only send to each address once per send operation. - + Duplicate address found, can only send to each address once per send operation. - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Error: Transaction creation failed! + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. SendCoinsEntry + Form - + Form + A&mount: - + A&mount: + Pay &To: - + Pay &To: + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book - + Enter a label for this address to add it to your address book + &Label: - - - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - + &Label: + Choose address from address book - + Choose address from address book + Alt+A - + Alt+A + Paste address from clipboard - + Paste address from clipboard + Alt+P - + Alt+P + Remove this recipient - + Remove this recipient - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) SignVerifyMessageDialog - Messaging - Sign / Verify a Message - + + Signatures - Sign / Verify a Message + Signatures - Sign / Verify a Message + &Sign Message - + &Sign Message + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + Choose an address from the address book - + Choose an address from the address book + + Alt+A - + Alt+A + Paste address from clipboard - + Paste address from clipboard + Alt+P - + Alt+P + Enter the message you want to sign here - + Enter the message you want to sign here + + Signature + Signature + + + Copy the current signature to the system clipboard - + Copy the current signature to the system clipboard - Sign the message to prove you own this Bitcoin address - + + Sign the message to prove you own this CasinoCoin address + Sign the message to prove you own this CasinoCoin address + + Sign &Message + Sign &Message + + + Reset all sign message fields - + Reset all sign message fields + + Clear &All - + Clear &All + &Verify Message - + &Verify Message + Enter the signing 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. - + Enter the signing 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. - The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) - Verify the message to ensure it was signed with the specified Bitcoin address - + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verify the message to ensure it was signed with the specified CasinoCoin address + + Verify &Message + Verify &Message + + + Reset all verify message fields - + Reset all verify message fields - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Click "Sign Message" to generate signature - + Click "Sign Message" to generate signature - Enter Bitcoin signature - + + Enter CasinoCoin signature + Enter CasinoCoin signature + + The entered address is invalid. - + The entered address is invalid. + + + + Please check the address and try again. - + Please check the address and try again. + + The entered address does not refer to a key. - + The entered address does not refer to a key. - Wallet unlock was canceled. - + + Wallet unlock was cancelled. + Wallet unlock was cancelled. + Private key for the entered address is not available. - + Private key for the entered address is not available. + Message signing failed. - + Message signing failed. + Message signed. - + Message signed. + The signature could not be decoded. - + The signature could not be decoded. + + Please check the signature and try again. - + Please check the signature and try again. + The signature did not match the message digest. - + The signature did not match the message digest. + Message verification failed. - + Message verification failed. + Message verified. - + Message verified. + + + + SplashScreen + + + The CasinoCoin developers + The CasinoCoin developers + + + + [testnet] + [testnet] TransactionDesc + Open until %1 - - - - Open for %n block(s) - - Open for %n block - Open for %n blocks - + Open until %1 + %1/offline - + %1/offline + %1/unconfirmed - + %1/unconfirmed + %1 confirmations - + %1 confirmations + Status - + Status + , broadcast through %n node(s) , broadcast through %n node @@ -1293,38 +1708,55 @@ Address: %4 + Date - + Date + Source - + Source + Generated - + Generated + + From - + From + + + To - + To + + own address - + own address + label - + label + + + + + Credit - + Credit + matures in %n more block(s) matures in %n more block @@ -1332,123 +1764,162 @@ Address: %4 + not accepted - + not accepted + + + + Debit - + Debit + Transaction fee - + Transaction fee + Net amount - + Net amount + Message - + Message + Comment - + Comment + Transaction ID - + Transaction ID - Generated coins must mature 8 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. - + + Generated coins must mature 120 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. + Generated coins must mature 120 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. + Debug information - + Debug information + Transaction - + Transaction + Inputs - + Inputs + Amount - + Amount + true - + true + false - + false + , has not been successfully broadcast yet - + , has not been successfully broadcast yet + + + + Open for %n more block(s) + + Open for %n more block + Open for %n more blocks + + unknown - + unknown TransactionDescDialog + Transaction details - + Transaction details + This pane shows a detailed description of the transaction - + This pane shows a detailed description of the transaction TransactionTableModel + Date - + Date + Type - + Type + Address - + Address + Amount - + Amount - Open for %n block(s) + + Open for %n more block(s) - Open for %n block - Open for %n blocks + Open for %n more block + Open for %n more blocks + Open until %1 - + Open until %1 + Offline (%1 confirmations) - + Offline (%1 confirmations) + Unconfirmed (%1 of %2 confirmations) - + Unconfirmed (%1 of %2 confirmations) + Confirmed (%1 confirmations) - + Confirmed (%1 confirmations) + Mined balance will be available when it matures in %n more block(s) Mined balance will be available when it matures in %n more block @@ -1456,631 +1927,1041 @@ Address: %4 + This block was not received by any other nodes and will probably not be accepted! - + This block was not received by any other nodes and will probably not be accepted! + Generated but not accepted - + Generated but not accepted + Received with - + Received with + Received from - + Received from + Sent to - + Sent to + Payment to yourself - + Payment to yourself + Mined - + Mined + (n/a) - + (n/a) + Transaction status. Hover over this field to show number of confirmations. - + Transaction status. Hover over this field to show number of confirmations. + Date and time that the transaction was received. - + Date and time that the transaction was received. + Type of transaction. - + Type of transaction. + Destination address of transaction. - + Destination address of transaction. + Amount removed from or added to balance. - + Amount removed from or added to balance. TransactionView + + All - + All + Today - + Today + This week - + This week + This month - + This month + Last month - + Last month + This year - + This year + Range... - + Range... + Received with - + Received with + Sent to - + Sent to + To yourself - + To yourself + Mined - + Mined + Other - + Other + Enter address or label to search - + Enter address or label to search + Min amount - + Min amount + Copy address - + Copy address + Copy label - + Copy label + Copy amount - + Copy amount + + Copy transaction ID + Copy transaction ID + + + Edit label - + Edit label + Show transaction details - + Show transaction details + Export Transaction Data - + Export Transaction Data + Comma separated file (*.csv) - + Comma separated file (*.csv) + Confirmed - + Confirmed + Date - + Date + Type - + Type + Label - + Label + Address - + Address + Amount - + Amount + ID - + ID + Error exporting - + Error exporting + Could not write to file %1. - + Could not write to file %1. + Range: - + Range: + to - + to WalletModel - Sending... - + + Send Coins + Send Coins + + + + WalletView + + + &Export + &Export + + + + Export the data in the current tab to a file + Export the data in the current tab to a file + + + + Backup Wallet + Backup Wallet + + + + Wallet Data (*.dat) + Wallet Data (*.dat) + + + + Backup Failed + Backup Failed + + + + There was an error trying to save the wallet data to the new location. + There was an error trying to save the wallet data to the new location. + + + + Backup Successful + Backup Successful + + + + The wallet data was successfully saved to the new location. + The wallet data was successfully saved to the new location. bitcoin-core - Bitcoin version - + + CasinoCoin version + CasinoCoin version + Usage: - + Usage: - Send command to -server or bitcoind - + + Send command to -server or casinocoind + Send command to -server or casinocoind + List commands - + List commands + Get help for a command - + Get help for a command + Options: - + Options: - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Specify configuration file (default: casinocoin.conf) - Specify pid file (default: bitcoind.pid) - - - - Generate coins - - - - Don't generate coins - + + Specify pid file (default: casinocoind.pid) + Specify pid file (default: casinocoind.pid) + Specify data directory - + Specify data directory + Set database cache size in megabytes (default: 25) - + Set database cache size in megabytes (default: 25) - Set database disk log size in megabytes (default: 100) - - - - Specify connection timeout (in milliseconds) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Listen for connections on <port> (default: 47950 or testnet: 17950) + Maintain at most <n> connections to peers (default: 125) - + Maintain at most <n> connections to peers (default: 125) + Connect to a node to retrieve peer addresses, and disconnect - + Connect to a node to retrieve peer addresses, and disconnect + Specify your own public address - - - - Bind to given address. Use [host]:port notation for IPv6 - + Specify your own public address + Threshold for disconnecting misbehaving peers (default: 100) - + Threshold for disconnecting misbehaving peers (default: 100) + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - Detach block and address databases. Increases shutdown time (default: 0) - + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + Accept command line and JSON-RPC commands - + Accept command line and JSON-RPC commands + Run in the background as a daemon and accept commands - + Run in the background as a daemon and accept commands + Use the test network - + Use the test network + Accept connections from outside (default: 1 if no -proxy or -connect) - - - - Connect only to the specified node(s) - - - - Discover own IP address (default: 1 when listening and no -externalip) - - - - Failed to listen on any port. Use -listen=0 if you want this. - - - - Find peers using DNS lookup (default: 1 unless -connect) - - - - Invalid -tor address: '%s' - - - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) - - - - Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) - - - - Only connect to nodes in network <net> (IPv4, IPv6 or Tor) - - - - Output extra debugging information. Implies all other -debug* options - - - - Output extra network debugging information - - - - Prepend debug output with timestamp - - - - Select the version of socks proxy to use (4-5, default: 5) - - - - Send trace/debug info to console instead of debug.log file - - - - Send trace/debug info to debugger - - - - Use UPnP to map the listening port (default: 0) - - - - Use UPnP to map the listening port (default: 1 when listening) - - - - Use proxy to reach tor hidden services (default: same as -proxy) - - - - Username for JSON-RPC connections - - - - Warning: this version is obsolete, upgrade required - - - - Password for JSON-RPC connections - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - Allow JSON-RPC connections from specified IP address - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - Upgrade wallet to latest format - - - - Set key pool size to <n> (default: 100) - - - - Rescan the block chain for missing wallet transactions - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - How thorough the block verification is (0-6, default: 1) - - - - Imports blocks from external blk000?.dat file - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - Use OpenSSL (https) for JSON-RPC connections - - - - Server certificate file (default: server.cert) - - - - Server private key (default: server.pem) - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - - - - This help message - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - Bitcoin - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - Connect through socks proxy - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - Loading addresses... - - - - Error loading blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - Error loading wallet.dat - - - - Invalid -proxy address: '%s' - - - - Unknown network specified in -onlynet: '%s' - - - - Unknown -socks proxy version requested: %i - - - - Cannot resolve -bind address: '%s' - - - - Cannot resolve -externalip address: '%s' - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - Error: could not start node - - - - Error: Wallet locked, unable to create transaction - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - Error: Transaction creation failed - - - - Sending... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - Invalid amount - - - - Insufficient funds - - - - Loading block index... - - - - Add a node to connect to and attempt to keep the connection open - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - Find peers using internet relay chat (default: 0) - - - - Fee per KB to add to transactions you send - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - Loading wallet... - - - - Cannot downgrade wallet - - - - Cannot initialize keypool - - - - Cannot write default address - - - - Rescanning... - - - - Done loading - - - - To use the %s option - + Accept connections from outside (default: 1 if no -proxy or -connect) + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + Attempt to recover private keys from a corrupt wallet.dat + Attempt to recover private keys from a corrupt wallet.dat + + + + Block creation options: + Block creation options: + + + + Connect only to the specified node(s) + Connect only to the specified node(s) + + + + Corrupted block database detected + Corrupted block database detected + + + + Discover own IP address (default: 1 when listening and no -externalip) + Discover own IP address (default: 1 when listening and no -externalip) + + + + Do you want to rebuild the block database now? + Do you want to rebuild the block database now? + + + + Error initializing block database + Error initializing block database + + + + Error initializing wallet database environment %s! + Error initializing wallet database environment %s! + + + + Error loading block database + Error loading block database + + + + Error opening block database + Error opening block database + + + + Error: Disk space is low! + Error: Disk space is low! + + + + Error: Wallet locked, unable to create transaction! + Error: Wallet locked, unable to create transaction! + + + + Error: system error: + Error: system error: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Failed to listen on any port. Use -listen=0 if you want this. + + + + Failed to read block info + Failed to read block info + + + + Failed to read block + Failed to read block + + + + Failed to sync block index + Failed to sync block index + + + + Failed to write block index + Failed to write block index + + + + Failed to write block info + Failed to write block info + + + + Failed to write block + Failed to write block + + + + Failed to write file info + Failed to write file info + + + + Failed to write to coin database + Failed to write to coin database + + + + Failed to write transaction index + Failed to write transaction index + + + + Failed to write undo data + Failed to write undo data + + + + Find peers using DNS lookup (default: 1 unless -connect) + Find peers using DNS lookup (default: 1 unless -connect) + + + + Generate coins (default: 0) + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + How many blocks to check at startup (default: 288, 0 = all) + + + + How thorough the block verification is (0-4, default: 3) + How thorough the block verification is (0-4, default: 3) + + + + Not enough file descriptors available. + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files + Rebuild block chain index from current blk000??.dat files + + + + Set the number of threads to service RPC calls (default: 4) + Set the number of threads to service RPC calls (default: 4) + + + + Verifying blocks... + Verifying blocks... + + + + Verifying wallet... + Verifying wallet... + + + + Imports blocks from external blk000??.dat file + Imports blocks from external blk000??.dat file + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information + Information + + + + Invalid -tor address: '%s' + Invalid -tor address: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Invalid amount for -mintxfee=<amount>: '%s' + + + + Maintain a full transaction index (default: 0) + Maintain a full transaction index (default: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Only accept block chain matching built-in checkpoints (default: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + Output extra debugging information. Implies all other -debug* options + Output extra debugging information. Implies all other -debug* options + + + + Output extra network debugging information + Output extra network debugging information + + + + Prepend debug output with timestamp + Prepend debug output with timestamp + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + Select the version of socks proxy to use (4-5, default: 5) + Select the version of socks proxy to use (4-5, default: 5) + + + + Send trace/debug info to console instead of debug.log file + Send trace/debug info to console instead of debug.log file + + + + Send trace/debug info to debugger + Send trace/debug info to debugger + + + + Set maximum block size in bytes (default: 250000) + Set maximum block size in bytes (default: 250000) + + + + Set minimum block size in bytes (default: 0) + Set minimum block size in bytes (default: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + Signing transaction failed + Signing transaction failed + + + + Specify connection timeout in milliseconds (default: 5000) + Specify connection timeout in milliseconds (default: 5000) + + + + System error: + System error: + + + + Transaction amount too small + Transaction amount too small + + + + Transaction amounts must be positive + Transaction amounts must be positive + + + + Transaction too large + Transaction too large + + + + Use UPnP to map the listening port (default: 0) + Use UPnP to map the listening port (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Use UPnP to map the listening port (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Use proxy to reach tor hidden services (default: same as -proxy) + + + + Username for JSON-RPC connections + Username for JSON-RPC connections + + + + Warning + Warning + + + + Warning: This version is obsolete, upgrade required! + Warning: This version is obsolete, upgrade required! + + + + You need to rebuild the databases using -reindex to change -txindex + You need to rebuild the databases using -reindex to change -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat corrupt, salvage failed + + + + Password for JSON-RPC connections + Password for JSON-RPC connections + + + + Allow JSON-RPC connections from specified IP address + Allow JSON-RPC connections from specified IP address + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Send commands to node running on <ip> (default: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + Upgrade wallet to latest format + Upgrade wallet to latest format + + + + Set key pool size to <n> (default: 100) + Set key pool size to <n> (default: 100) + + + + Rescan the block chain for missing wallet transactions + Rescan the block chain for missing wallet transactions + + + + Use OpenSSL (https) for JSON-RPC connections + Use OpenSSL (https) for JSON-RPC connections + + + + Server certificate file (default: server.cert) + Server certificate file (default: server.cert) + + + + Server private key (default: server.pem) + Server private key (default: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + This help message + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + Connect through socks proxy + Connect through socks proxy + + + + Allow DNS lookups for -addnode, -seednode and -connect + Allow DNS lookups for -addnode, -seednode and -connect + + + + Loading addresses... + Loading addresses... + + + + Error loading wallet.dat: Wallet corrupted + Error loading wallet.dat: Wallet corrupted + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + Error loading wallet.dat + Error loading wallet.dat + + + + Invalid -proxy address: '%s' + Invalid -proxy address: '%s' + + + + Unknown network specified in -onlynet: '%s' + Unknown network specified in -onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + Unknown -socks proxy version requested: %i + + + + Cannot resolve -bind address: '%s' + Cannot resolve -bind address: '%s' + + + + Cannot resolve -externalip address: '%s' + Cannot resolve -externalip address: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Invalid amount for -paytxfee=<amount>: '%s' + + + + Invalid amount + Invalid amount + + + + Insufficient funds + Insufficient funds + + + + Loading block index... + Loading block index... + + + + Add a node to connect to and attempt to keep the connection open + Add a node to connect to and attempt to keep the connection open + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + Fee per KB to add to transactions you send + Fee per KB to add to transactions you send + + + + Loading wallet... + Loading wallet... + + + + Cannot downgrade wallet + Cannot downgrade wallet + + + + Cannot write default address + Cannot write default address + + + + Rescanning... + Rescanning... + + + + Done loading + Done loading + + + + To use the %s option + To use the %s option + + + Error - - - - An error occured while setting up the RPC port %i for listening: %s - + Error + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts new file mode 100644 index 0000000..a48fd08 --- /dev/null +++ b/src/qt/locale/bitcoin_eo.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + Pri CasinoCoin + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b>-a versio + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + Adresaro + + + + Double-click to edit address or label + Duoble-klaku por redakti adreson aŭ etikedon + + + + Create a new address + Kreu novan adreson + + + + Copy the currently selected address to the system clipboard + Kopiu elektitan adreson al la tondejo + + + + &New Address + &Nova Adreso + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + &Kopiu Adreson + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + &Forviŝu + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + Kopiu &Etikedon + + + + &Edit + &Redaktu + + + + Send &Coins + + + + + Export Address Book Data + Eksportu Adresarajn Datumojn + + + + Comma separated file (*.csv) + Diskoma dosiero (*.csv) + + + + Error exporting + Eraro dum eksportado + + + + Could not write to file %1. + Ne eblis skribi al dosiero %1. + + + + AddressTableModel + + + Label + Etikedo + + + + Address + Adreso + + + + (no label) + (ne etikedo) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + Enigu pasfrazon + + + + New passphrase + Nova pasfrazo + + + + Repeat new passphrase + Ripetu novan pasfrazon + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Enigu novan pasfrazon por la monujo.<br/>Bonvolu, uzu pasfrazon kun <b>10 aŭ pli hazardaj signoj</b>, aŭ <b>ok aŭ pli vortoj</b>. + + + + Encrypt wallet + Ĉifru monujon + + + + This operation needs your wallet passphrase to unlock the wallet. + Ĉi tiu operacio devas vian monujan pasfrazon, por malŝlosi la monujon. + + + + Unlock wallet + Malŝlosu monujon + + + + This operation needs your wallet passphrase to decrypt the wallet. + Ĉi tiu operacio devas vian monujan pasfrazon, por malĉifri la monujon. + + + + Decrypt wallet + Malĉifru monujon + + + + Change passphrase + Anstataŭigu pasfrazon + + + + Enter the old and new passphrase to the wallet. + Enigu la malnovan kaj novan monujan pasfrazon. + + + + Confirm wallet encryption + Konfirmu ĉifrado de monujo + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + Monujo ĉifrita + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + Monujo ĉifrado fiaskis + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Ĉifrado de monujo fiaskis, kaŭze de interna eraro. Via monujo ne ĉifritas. + + + + + The supplied passphrases do not match. + La pasfrazoj enigitaj ne samas. + + + + Wallet unlock failed + Monujo malŝlosado fiaskis + + + + + + The passphrase entered for the wallet decryption was incorrect. + La pasfrazo enigita por ĉifrado de monujo ne konformas. + + + + Wallet decryption failed + Monujo malĉifrado fiaskis + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + Subskribu &mesaĝon... + + + + Synchronizing with network... + Sinkronigante kun reto... + + + + &Overview + &Superrigardo + + + + Show general overview of wallet + + + + + &Transactions + &Transakcioj + + + + Browse transaction history + Esploru historion de transakcioj + + + + Edit the list of stored addresses and labels + + + + + Show the list of addresses for receiving payments + + + + + E&xit + &Eliru + + + + Quit application + Eliru de aplikaĵo + + + + Show information about CasinoCoin + Vidigu informaĵon pri Bitmono + + + + About &Qt + Pri &QT + + + + Show information about Qt + Vidigu informaĵon pri Qt + + + + &Options... + &Opcioj... + + + + &Encrypt Wallet... + &Ĉifru Monujon... + + + + &Backup Wallet... + + + + + &Change Passphrase... + &Anstataŭigu pasfrazon... + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + &Kontrolu mesaĝon... + + + + + CasinoCoin + + + + + Wallet + Monujo + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + &Dosiero + + + + &Settings + &Agordoj + + + + &Help + &Helpo + + + + Tabs toolbar + + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + %n horo%n horoj + + + + %n day(s) + %n tago%n tagoj + + + + %n week(s) + %n semajno%n semajnoj + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + Eraro + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + Ĝisdata + + + + Catching up... + Ĝisdatigante... + + + + Confirm transaction fee + + + + + Sent transaction + Sendita transakcio + + + + Incoming transaction + Envenanta transakcio + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Monujo estas <b>ĉifrita</b> kaj nun <b>malŝlosita</b> + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Monujo estas <b>ĉifrita</b> kaj nun <b>ŝlosita</b> + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + Reta Averto + + + + EditAddressDialog + + + Edit Address + Redaktu Adreson + + + + &Label + &Etikedo + + + + The label associated with this address book entry + La etikedo interrilatita kun ĉi tiun adreso + + + + &Address + &Adreso + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + La adreso enigita "%1" jam ekzistas en la adresaro. + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + Ne eblis malŝlosi monujon + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + CasinoCoin-Qt + + + + version + versio + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + Opcioj + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + &OK + + + + &Cancel + &Nuligu + + + + &Apply + &Apliku + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + Nekonfirmita: + + + + Wallet + Monujo + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + <b>Lastaj transakcioj</b> + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + Etikedo: + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + Reto + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + &Malfermu + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + Sendu Monojn + + + + Send to multiple recipients at once + Sendu samtempe al multaj ricevantoj + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + 123,456 BTC + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + <b>%1</b> al %2 (%3) + + + + Confirm send coins + + + + + Are you sure you want to send %1? + Ĉu vi vere volas sendi %1? + + + + and + kaj + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + &Etikedo: + + + + Choose address from address book + Elektu adreson el adresaro + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Algluu adreson de tondejo + + + + Alt+P + Alt+P + + + + Remove this recipient + Forigu ĉi tiun ricevanton + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Algluu adreson de tondejo + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + %1/nekonfirmita + + + + %1 confirmations + %1 konfirmoj + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + Dato + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + Sumo + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + , ankoraŭ ne elsendita sukcese + + + + Open for %n more block(s) + + + + + unknown + nekonata + + + + TransactionDescDialog + + + Transaction details + Transakciaj detaloj + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + Dato + + + + Type + Tipo + + + + Address + Adreso + + + + Amount + Sumo + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + Ricevita kun + + + + Received from + Ricevita de + + + + Sent to + Sendita al + + + + Payment to yourself + Pago al vi mem + + + + Mined + Minita + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + Transakcia tipo. + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + Ĉiuj + + + + Today + Hodiaŭ + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + Ricevita kun + + + + Sent to + Sendita al + + + + To yourself + Al vi mem + + + + Mined + Minita + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + Kopiu adreson + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + Redaktu etikedon + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + Diskoma dosiero (*.csv) + + + + Confirmed + Konfirmita + + + + Date + Dato + + + + Type + Tipo + + + + Label + Etikedo + + + + Address + Adreso + + + + Amount + Sumo + + + + ID + + + + + Error exporting + Eraro dum eksportado + + + + Could not write to file %1. + Ne eblis skribi al dosiero %1. + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + CasinoCoin-a versio + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + Listigu instrukciojn + + + + Get help for a command + + + + + Options: + Opcioj: + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + Ŝarĝante adresojn... + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + Ŝarĝante blok-indekson... + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + Ŝarĝante monujon... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + Ŝarĝado finitas + + + + To use the %s option + Por uzi la opcion %s + + + + Error + Eraro + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 2636d19..c70a886 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -3,122 +3,163 @@ AboutDialog - - About Bitcoin - Acerca de Bitcoin + + About CasinoCoin + Acerca de CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versión + + <b>CasinoCoin</b> version + Versión de <b>CasinoCoin</b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Desarrolladores de Bitcoin ⏎ -⏎ -Este software es experimental. ⏎ -⏎ -Se distribuye bajo la licencia de software MIT/X11, consulte el archivo adjunto o license.txt http://www.opensource.org/licenses/mit-license.php. ⏎ -⏎ -Este producto incluye software desarrollado por el OpenSSL Project para su uso en el OpenSSL Toolkit (http://www.openssl.org/~~V) y software de criptografía escrito por Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. + +Este es un software experimental. + +Distribuido bajo la licencia MIT/X11, vea el archivo adjunto +COPYING o http://www.opensource.org/licenses/mit-license.php. + +Este producto incluye software desarrollado por OpenSSL Project para su uso en +el OpenSSL Toolkit (http://www.openssl.org/) y software criptográfico escrito por +Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers + Los programadores CasinoCoin AddressBookPage - + Address Book Libreta de direcciones - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Éstas son sus direcciones Bitcoin para recibir pagos. Puede usar una diferente para cada persona emisora para saber quién le está pagando. - - - + Double-click to edit address or label Haga doble clic para editar una dirección o etiqueta - + Create a new address Crear una nueva dirección - + Copy the currently selected address to the system clipboard - Copiar la dirección seleccionada al portapapeles + Copiar la dirección seleccionada al portapapeles del sistema - + &New Address &Añadir dirección - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Estas son sus direcciones CasinoCoin para recibir pagos. Puede utilizar una diferente por cada persona emisora para saber quién le está pagando. + + + &Copy Address &Copiar dirección - + Show &QR Code Mostrar código &QR - - Sign a message to prove you own this address - Firmar un mensaje para demostrar que posee esta dirección + + Sign a message to prove you own a CasinoCoin address + Firmar un mensaje para demostrar que se posee una dirección CasinoCoin - - &Sign Message + + Sign &Message &Firmar mensaje - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Borrar de la lista la dirección seleccionada . Sólo se pueden borrar las direcciones de envío. + + Delete the currently selected address from the list + Borrar de la lista la dirección seleccionada - + + Export the data in the current tab to a file + Exportar a un archivo los datos de esta pestaña + + + + &Export + &Exportar + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verificar un mensaje para comprobar que fue firmado con la dirección CasinoCoin indicada + + + + &Verify Message + &Verificar mensaje + + + &Delete - &Borrar + &Eliminar - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Estas son sus direcciones CasinoCoin para enviar pagos. Compruebe siempre la cantidad y la dirección receptora antes de transferir monedas. + + + Copy &Label Copiar &etiqueta - + &Edit &Editar - + + Send &Coins + Enviar &monedas + + + Export Address Book Data Exportar datos de la libreta de direcciones - + Comma separated file (*.csv) Archivos de columnas separadas por coma (*.csv) - + Error exporting Error al exportar - + Could not write to file %1. No se pudo escribir en el archivo %1. @@ -126,17 +167,17 @@ Este producto incluye software desarrollado por el OpenSSL Project para su uso e AddressTableModel - + Label Etiqueta - + Address Dirección - + (no label) (sin etiqueta) @@ -144,432 +185,460 @@ Este producto incluye software desarrollado por el OpenSSL Project para su uso e AskPassphraseDialog - + Passphrase Dialog - + Diálogo de contraseña - + Enter passphrase - Contraseña actual + Introducir contraseña - + New passphrase Nueva contraseña - + Repeat new passphrase Repita la nueva contraseña - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Introduzca la nueva contraseña del monedero.<br/>Por favor elija una con <b>10 o más caracteres aleatorios</b> u <b>ocho o más palabras</b>. - + Encrypt wallet Cifrar el monedero - + This operation needs your wallet passphrase to unlock the wallet. - Para desbloquear el monedero esta operación necesita de su contraseña. + Esta operación requiere su contraseña para desbloquear el monedero. - + Unlock wallet Desbloquear monedero - + This operation needs your wallet passphrase to decrypt the wallet. - Para descifrar el monedero esta operación necesita de su contraseña. + Esta operación requiere su contraseña para descifrar el monedero. - + Decrypt wallet - Descifrar monedero + Descifrar el monedero - + Change passphrase Cambiar contraseña - + Enter the old and new passphrase to the wallet. Introduzca la contraseña anterior del monedero y la nueva. - + Confirm wallet encryption Confirmar cifrado del monedero - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ATENCIÓN: ¡Si cifra el monedero y pierde la contraseña perderá <b>TODOS SUS BITCOINS</b>!" -¿Está seguro de querer cifrarlo? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Atencion: ¡Si cifra su monedero y pierde la contraseña perderá <b>TODOS SUS CASINOCOINS</b>!" - - + + Are you sure you wish to encrypt your wallet? + ¿Seguro que desea cifrar su monedero? + + + + 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. + IMPORTANTE: Cualquier copia de seguridad que haya realizado previamente de su archivo de monedero debe reemplazarse con el nuevo archivo de monedero cifrado. Por razones de seguridad, las copias de seguridad previas del archivo de monedero no cifradas serán inservibles en cuanto comience a usar el nuevo monedero cifrado. + + + + + Warning: The Caps Lock key is on! + Aviso: ¡La tecla de bloqueo de mayúsculas está activada! + + + + Wallet encrypted Monedero cifrado - - Bitcoin 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. - Bitcoin cerrará al finalizar el proceso de cifrado. Recuerde que el cifrado de su monedero no puede proteger totalmente sus bitcoin de ser robados por el malware que infecte su sistema. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin se cerrará para finalizar el proceso de cifrado. Recuerde que el cifrado de su monedero no puede proteger totalmente sus casinocoins de robo por malware que infecte su sistema. - - - Warning: The Caps Lock key is on. - Aviso: el bloqueo de mayúsculas está activado. - - - - - - + + + + Wallet encryption failed Ha fallado el cifrado del monedero - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Ha fallado el cifrado del monedero debido a un error interno. El monedero no ha sido cifrado. - - + + The supplied passphrases do not match. Las contraseñas no coinciden. - + Wallet unlock failed Ha fallado el desbloqueo del monedero - - - + + + The passphrase entered for the wallet decryption was incorrect. La contraseña introducida para descifrar el monedero es incorrecta. - + Wallet decryption failed Ha fallado el descifrado del monedero - - Wallet passphrase was succesfully changed. - La contraseña del monedero ha sido cambiada correctamente. + + Wallet passphrase was successfully changed. + Se ha cambiado correctamente la contraseña del monedero. BitcoinGUI - - Bitcoin Wallet - Monedero Bitcoin - - - + Sign &message... Firmar &mensaje... - - Show/Hide &Bitcoin - Mostrar/ocultar &Bitcoin - - - + Synchronizing with network... Sincronizando con la red… - + &Overview &Vista general - + Show general overview of wallet Mostrar vista general del monedero - + &Transactions &Transacciones - + Browse transaction history Examinar el historial de transacciones - - &Address Book - &Libreta de direcciones - - - + Edit the list of stored addresses and labels Editar la lista de las direcciones y etiquetas almacenadas - - &Receive coins - &Recibir monedas - - - + Show the list of addresses for receiving payments Mostrar la lista de direcciones utilizadas para recibir pagos - - &Send coins - &Enviar monedas - - - - Prove you control an address - Demuestre que controla una dirección - - - + E&xit &Salir - + Quit application Salir de la aplicación - - &About %1 - &Acerca de %1 + + Show information about CasinoCoin + Mostrar información acerca de CasinoCoin - - Show information about Bitcoin - Mostrar información acerca de Bitcoin - - - + About &Qt Acerca de &Qt - + Show information about Qt Mostrar información acerca de Qt - + &Options... &Opciones... - + &Encrypt Wallet... &Cifrar monedero… - + &Backup Wallet... Copia de &respaldo del monedero... - + &Change Passphrase... &Cambiar la contraseña… - - - ~%n block(s) remaining - ~%n bloque restante~%n bloques restantes + + + Importing blocks from disk... + Importando bloques de disco... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Descargado %1 de %2 bloques del historial de transacciones (%3% hecho). + + Reindexing blocks on disk... + Reindexando bloques en disco... - - &Export... - &Exportar… + + Send coins to a CasinoCoin address + Enviar monedas a una dirección CasinoCoin - - Send coins to a Bitcoin address - + + Modify configuration options for CasinoCoin + Modificar las opciones de configuración de CasinoCoin - - Modify configuration options for Bitcoin - - - - - Show or hide the Bitcoin window - Mostrar u ocultar la ventana Bitcoin - - - - Export the data in the current tab to a file - Exportar a un archivo los datos de esta pestaña - - - - Encrypt or decrypt wallet - Cifrar o descifrar el monedero - - - + Backup wallet to another location Copia de seguridad del monedero en otra ubicación - + Change the passphrase used for wallet encryption Cambiar la contraseña utilizada para el cifrado del monedero - + &Debug window Ventana de &depuración - + Open debugging and diagnostic console Abrir la consola de depuración y diagnóstico - + &Verify message... - + &Verificar mensaje... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Monedero + + + + &Send + &Enviar + + + + &Receive + &Recibir + + + + &Addresses + &Direcciones + + + + &About CasinoCoin + &Acerca de CasinoCoin + + + + &Show / Hide + Mo&strar/ocultar + + + + Show or hide the main Window + Mostrar u ocultar la ventana principal + + + + Encrypt the private keys that belong to your wallet + Cifrar las claves privadas de su monedero + + + + Sign messages with your CasinoCoin addresses to prove you own them + Firmar mensajes con sus direcciones CasinoCoin para demostrar la propiedad + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verificar mensajes comprobando que están firmados con direcciones CasinoCoin concretas + + + &File &Archivo - + &Settings &Configuración - + &Help A&yuda - + Tabs toolbar Barra de pestañas - - Actions toolbar - Barra de acciones - - - - + + [testnet] [testnet] - - - Bitcoin client - cliente Bitcoin + + CasinoCoin client + Cliente CasinoCoin - - %n active connection(s) to Bitcoin network - %n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin + + %n active connection(s) to CasinoCoin network + %n conexión activa hacia la red CasinoCoin%n conexiones activas hacia la red CasinoCoin - - Downloaded %1 blocks of transaction history. - Se han bajado %1 bloques de historial. - - - - %n second(s) ago - hace %n segundohace %n segundos - - - - %n minute(s) ago - hace %n minutohace %n minutos - - - - %n hour(s) ago - hace %n horahace %n horas - - - - %n day(s) ago - hace %n díahace %n días + + No block source available... + Ninguna fuente de bloques disponible ... - + + Processed %1 of %2 (estimated) blocks of transaction history. + Se han procesado %1 de %2 bloques (estimados) del historial de transacciones. + + + + Processed %1 blocks of transaction history. + Procesados %1 bloques del historial de transacciones. + + + + %n hour(s) + %n hora%n horas + + + + %n day(s) + %n día%n días + + + + %n week(s) + %n semana%n semanas + + + + %1 behind + %1 atrás + + + + Last received block was generated %1 ago. + El último bloque recibido fue generado hace %1. + + + + Transactions after this will not yet be visible. + Las transacciones posteriores a esta aún no están visibles. + + + + Error + Error + + + + Warning + Aviso + + + + Information + Información + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Esta transacción supera el límite de tamaño. Puede enviarla con una comisión de %1, destinada a los nodos que procesen su transacción para contribuir al mantenimiento de la red. ¿Desea pagar esta comisión? + + + Up to date Actualizado - + Catching up... - Recuperando... + Actualizando... - - Last received block was generated %1. - El último bloque recibido fue generado %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Esta transacción supera el límite. Puede seguir enviándola incluyendo una comisión de %1 que se va a repartir entre los nodos que procesan su transacción y ayudan a mantener la red. ¿Desea pagar esa tarifa? - - - + Confirm transaction fee Confirme la tarifa de la transacción - + Sent transaction Transacción enviada - + Incoming transaction Transacción entrante - + Date: %1 Amount: %2 Type: %3 @@ -578,541 +647,489 @@ Address: %4 Fecha: %1 Cantidad: %2 Tipo: %3 -Dirección: %4 +Dirección: %4 + - + + + URI handling + Gestión de URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + ¡No se puede interpretar la URI! Esto puede deberse a una dirección CasinoCoin inválida o a parámetros de URI mal formados. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> El monedero está <b>cifrado</b> y actualmente <b>desbloqueado</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> El monedero está <b>cifrado</b> y actualmente <b>bloqueado</b> - - Backup Wallet - Copia de seguridad del monedero - - - - Wallet Data (*.dat) - Datos del monedero (*.dat) - - - - Backup Failed - La copia de seguridad ha fallado - - - - There was an error trying to save the wallet data to the new location. - Ha habido un error al intentar guardar los datos del monedero a la nueva ubicación. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Ha ocurrido un error fatal. Bitcoin no puede continuar con seguridad y se cerrará. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ha ocurrido un error crítico. CasinoCoin ya no puede continuar con seguridad y se cerrará. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Mostrado - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Elige la subdivisión por defecto para mostrar cantidaded en la interfaz cuando se envien monedas - - - - &Display addresses in transaction list - &Mostrar las direcciones en la lista de transsaciones - - - - Whether to show Bitcoin addresses in the transaction list - Mostrar las direcciones bitcoin en la lista de transacciones - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Alerta de red EditAddressDialog - + Edit Address Editar Dirección - + &Label &Etiqueta - + The label associated with this address book entry La etiqueta asociada con esta entrada en la libreta - + &Address &Dirección - + The address associated with this address book entry. This can only be modified for sending addresses. - La dirección asociada con esta entrada en la guia. Solo puede ser modificada para direcciones de envío. + La dirección asociada con esta entrada en la guía. Solo puede ser modificada para direcciones de envío. - + New receiving address Nueva dirección para recibir - + New sending address Nueva dirección para enviar - + Edit receiving address Editar dirección de recepción - + Edit sending address - Editar dirección de envio + Editar dirección de envío - + The entered address "%1" is already in the address book. La dirección introducida "%1" ya está presente en la libreta de direcciones. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + La dirección introducida "%1" no es una dirección CasinoCoin válida. - + Could not unlock wallet. No se pudo desbloquear el monedero. - + New key generation failed. Ha fallado la generación de la nueva clave. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versión - + Usage: Uso: - - options - + + command-line options + opciones de la línea de órdenes - + UI options - + Opciones GUI - + Set language, for example "de_DE" (default: system locale) - Establecer el idioma, por ejemplo, "es_ES" (por defecto: configuración regional del sistema) + Establecer el idioma, por ejemplo, "es_ES" (predeterminado: configuración regional del sistema) - + Start minimized Arrancar minimizado - + Show splash screen on startup (default: 1) - Mostrar pantalla de bienvenida en el inicio (por defecto: 1) - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Desconectar las bases de datos de bloques y direcciones al cerrar la aplicación. Implica que pueden moverse a otros directorios de datos pero ralentiza el cierre. El monedero siempre queda desconectado. - - - - Pay transaction &fee - Comisión de &transacciones - - - - Main - Principal - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Tarifa de transacción por KB opcional que ayuda a asegurarse de que sus transacciones se procesan rápidamente. La mayoría de las transacciones son de 1 KB. Tarifa de 0,01 recomendado. - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Usted puede firmar los mensajes con sus direcciones para demostrar que las posee. Tenga cuidado de no firmar cualquier cosa vaga, ya que los ataques de phishing pueden tratar de engañarle firmando su identidad a través de ellos. Solo firme declaraciones totalmente detalladas con las que usted esté de acuerdo. - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - La dirección para firmar el mensaje con (por ejemplo, 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Elige la dirección de la libreta - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Pega dirección desde portapapeles - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Introduzca el mensaje que desea firmar aquí - - - - Copy the current signature to the system clipboard - Copiar la firma actual al portapapeles del sistema - - - - &Copy Signature - &Copiar firma - - - - Reset all sign message fields - Limpiar todos los campos de mensaje de la firma - - - - Clear &All - Limpiar &todo - - - - Click "Sign Message" to get signature - Haga clic en "Firma Mensaje" para obtener la firma - - - - Sign a message to prove you own this address - Firmar un mensaje a demostrar que posee esta dirección - - - - &Sign Message - &Firme mensaje - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduce una dirección Bitcoin (ej. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Error en firmado - - - - %1 is not a valid address. - %1 no es una dirección válida. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - La clave privada de %1 no está disponible. - - - - Sign failed - Firma falló - - - - NetworkOptionsPage - - - Network - Red - - - - Map port using &UPnP - Mapea el puerto usando &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Intenta abrir el puerto adecuado en el router automáticamente. Esta opción solo funciona si el router soporta UPnP y está activado. - - - - &Connect through SOCKS4 proxy: - &Conecta atraves de un proxy SOCKS4: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Conecta a la red Bitcoin a través de un proxy SOCKS4 (ej. para conectar con la red Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - Dirección IP del proxy (ej. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Puerto del servidor proxy (ej. 1234) + Mostrar pantalla de bienvenida en el inicio (predeterminado: 1) OptionsDialog - + Options Opciones + + + &Main + &Principal + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Tarifa de transacción opcional por kB que ayuda a asegurar que sus transacciones sean procesadas rápidamente. La mayoría de transacciones son de 1kB. + + + + Pay transaction &fee + Comisión de &transacciones + + + + Automatically start CasinoCoin after logging in to the system. + Iniciar CasinoCoin automáticamente al encender el sistema. + + + + &Start CasinoCoin on system login + &Iniciar CasinoCoin al iniciar el sistema + + + + Reset all client options to default. + Restablecer todas las opciones del cliente a las predeterminadas. + + + + &Reset Options + &Restablecer opciones + + + + &Network + &Red + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Abrir automáticamente el puerto del cliente CasinoCoin en el router. Esta opción solo funciona si el router admite UPnP y está activado. + + + + Map port using &UPnP + Mapear el puerto usando &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Conectar a la red CasinoCoin a través de un proxy SOCKS (ej. para conectar con la red Tor) + + + + &Connect through SOCKS proxy: + &Conectar a través de un proxy SOCKS: + + + + Proxy &IP: + Dirección &IP del proxy: + + + + IP address of the proxy (e.g. 127.0.0.1) + Dirección IP del proxy (ej. 127.0.0.1) + + + + &Port: + &Puerto: + + + + Port of the proxy (e.g. 9050) + Puerto del servidor proxy (ej. 9050) + + + + SOCKS &Version: + &Versión SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Versión del proxy SOCKS (ej. 5) + + + + &Window + &Ventana + + + + Show only a tray icon after minimizing the window. + Minimizar la ventana a la bandeja de iconos del sistema. + + + + &Minimize to the tray instead of the taskbar + &Minimizar a la bandeja en vez de a la barra de tareas + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimizar en lugar de salir de la aplicación al cerrar la ventana.Cuando esta opción está activa, la aplicación solo se puede cerrar seleccionando Salir desde el menú. + + + + M&inimize on close + M&inimizar al cerrar + + + + &Display + &Interfaz + + + + User Interface &language: + I&dioma de la interfaz de usuario + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + El idioma de la interfaz de usuario puede establecerse aquí. Este ajuste se aplicará cuando se reinicie CasinoCoin. + + + + &Unit to show amounts in: + Mostrar las cantidades en la &unidad: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Elegir la subdivisión predeterminada para mostrar cantidades en la interfaz y cuando se envían monedas. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Mostrar o no las direcciones CasinoCoin en la lista de transacciones. + + + + &Display addresses in transaction list + &Mostrar las direcciones en la lista de transacciones + + + + &OK + &Aceptar + + + + &Cancel + &Cancelar + + + + &Apply + &Aplicar + + + + default + predeterminado + + + + Confirm options reset + Confirme el restablecimiento de las opciones + + + + Some settings may require a client restart to take effect. + Algunas configuraciones pueden requerir un reinicio del cliente para que sean efectivas. + + + + Do you want to proceed? + ¿Quiere proceder? + + + + + Warning + Aviso + + + + + This setting will take effect after restarting CasinoCoin. + Esta configuración tendrá efecto tras reiniciar CasinoCoin. + + + + The supplied proxy address is invalid. + La dirección proxy indicada es inválida. + OverviewPage - + Form Desde - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red CasinoCoin después de que se haya establecido una conexión , pero este proceso aún no se ha completado. - + Balance: - Balance: + Saldo: - - Number of transactions: - Número de movimientos: - - - + Unconfirmed: No confirmado(s): - + Wallet Monedero - + + Immature: + No disponible: + + + + Mined balance that has not yet matured + Saldo recién minado que aún no está disponible. + + + <b>Recent transactions</b> <b>Movimientos recientes</b> - + Your current balance - Tu balance actual + Su saldo actual - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Total de las transacciones que faltan por confirmar y que no se cuentan para el total general + Total de las transacciones que faltan por confirmar y que no contribuyen al saldo actual - - Total number of transactions in wallet - Número total de movimientos en el monedero - - - - + + out of sync - + desincronizado + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + No se pudo iniciar casinocoin: manejador de pago-al-clic QRCodeDialog - + QR Code Dialog - + Diálogo de códigos QR - - QR Code - Código QR - - - + Request Payment Solicitud de pago - + Amount: Cuantía: - - BTC - BTC - - - + Label: - Label: + Etiqueta: - + Message: Mensaje: - + &Save As... - &Guardar Como ... + &Guardar como... - + Error encoding URI into QR Code. Error al codificar la URI en el código QR. - - Resulting URI too long, try to reduce the text for label / message. - URI demasiado larga, trata de reducir el texto de la etiqueta / mensaje. + + The entered amount is invalid, please check. + La cantidad introducida es inválida. Compruébela, por favor. - + + Resulting URI too long, try to reduce the text for label / message. + URI esultante demasiado larga. Intente reducir el texto de la etiqueta / mensaje. + + + Save QR Code Guardar código QR - + PNG Images (*.png) Imágenes PNG (*.png) @@ -1120,453 +1137,713 @@ Dirección: %4 RPCConsole - - Bitcoin debug window - Ventana de depuración - - - + Client name Nombre del cliente - - - - - - - - - + + + + + + + + + + N/A N/D - + Client version Versión del cliente - + &Information - + &Información - - Client - + + Using OpenSSL version + Utilizando la versión OpenSSL - + Startup time - + Hora de inicio - + Network Red - + Number of connections Número de conexiones - + On testnet En la red de pruebas - + Block chain Cadena de bloques - + Current number of blocks Número actual de bloques - + Estimated total blocks Bloques totales estimados - + Last block time Hora del último bloque - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Abrir - + + Command-line options + Opciones de la línea de órdenes + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Mostrar el mensaje de ayuda de CasinoCoin-Qt que enumera las opciones disponibles de línea de órdenes para CasinoCoin. + + + + &Show + &Mostrar + + + &Console - + &Consola - + Build date Fecha de compilación - + + CasinoCoin - Debug window + CasinoCoin - Ventana de depuración + + + + CasinoCoin Core + Núcleo de CasinoCoin + + + + Debug log file + Archivo de registro de depuración + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Abrir el archivo de registro de depuración en el directorio actual de datos. Esto puede llevar varios segundos para archivos de registro grandes. + + + Clear console Borrar consola - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Bienvenido a la consola RPC de CasinoCoin - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Use las flechas arriba y abajo para navegar por el historial y <b>Control+L</b> para limpiar la pantalla. - + Type <b>help</b> for an overview of available commands. - + Escriba <b>help</b> para ver un resumen de los comandos disponibles. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Envía monedas + Enviar monedas - + Send to multiple recipients at once - Envía a multiples destinatarios de una vez + Enviar a multiples destinatarios de una vez - - &Add Recipient - &Añadir destinatario + + Add &Recipient + Añadir &destinatario - + Remove all transaction fields Eliminar todos los campos de las transacciones - + Clear &All Limpiar &todo - + Balance: - Balance: + Saldo: - + 123.456 BTC 123.456 BTC - + Confirm the send action - Confirma el envío + Confirmar el envío - - &Send - &Envía + + S&end + &Enviar - + <b>%1</b> to %2 (%3) - <b>%1</b> to %2 (%3) + <b>%1</b> a %2 (%3) - + Confirm send coins Confirmar el envío de monedas - + Are you sure you want to send %1? - Estas seguro que quieres enviar %1? + ¿Está seguro de que desea enviar %1? - + and y - - The recepient address is not valid, please recheck. - La dirección de destinatario no es válida, comprueba otra vez. + + The recipient address is not valid, please recheck. + La dirección de recepción no es válida, compruébela de nuevo. - + The amount to pay must be larger than 0. - La cantidad por pagar tiene que ser mayor 0. + La cantidad por pagar tiene que ser mayor de 0. - + The amount exceeds your balance. - + La cantidad sobrepasa su saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + El total sobrepasa su saldo cuando se incluye la tasa de envío de %1 - + Duplicate address found, can only send to each address once per send operation. - + Se ha encontrado una dirección duplicada. Solo se puede enviar a cada dirección una vez por operación de envío. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Error: ¡Ha fallado la creación de la transacción! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Error: transacción rechazada. Puede haber ocurrido si alguna de las monedas ya estaba gastada o si ha usado una copia de wallet.dat y las monedas se gastaron en la copia pero no se han marcado así aquí. SendCoinsEntry - + Form - Envio + Envío - + A&mount: Ca&ntidad: - + Pay &To: &Pagar a: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + La dirección a la que enviar el pago (p. ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Etiquete esta dirección para añadirla a la libreta - + &Label: &Etiqueta: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - La dirección donde enviar el pago (ej. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Elija una dirección de la libreta de direcciones - + Alt+A Alt+A - + Paste address from clipboard - Pega dirección desde portapapeles + Pegar dirección desde portapapeles - + Alt+P Alt+P - + Remove this recipient - Elimina destinatario + Eliminar destinatario - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduce una dirección Bitcoin (ej. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduzca una dirección CasinoCoin (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Firmas - Firmar / verificar un mensaje + + + + &Sign Message + &Firmar mensaje + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Puede firmar mensajes con sus direcciones para demostrar que las posee. Tenga cuidado de no firmar cualquier cosa vaga, ya que los ataques de phishing pueden tratar de engañarle para suplantar su identidad. Firme solo declaraciones totalmente detalladas con las que usted esté de acuerdo. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + La dirección con la que firmar el mensaje (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Elija una dirección de la libreta de direcciones + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Pegar dirección desde portapapeles + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Introduzca el mensaje que desea firmar aquí + + + + Signature + Firma + + + + Copy the current signature to the system clipboard + Copiar la firma actual al portapapeles del sistema + + + + Sign the message to prove you own this CasinoCoin address + Firmar el mensaje para demostrar que se posee esta dirección CasinoCoin + + + + Sign &Message + Firmar &mensaje + + + + Reset all sign message fields + Limpiar todos los campos de la firma de mensaje + + + + + Clear &All + Limpiar &todo + + + + &Verify Message + &Verificar mensaje + + + + Enter the signing 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. + 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. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + La dirección con la que se firmó el mensaje (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verificar el mensaje para comprobar que fue firmado con la dirección CasinoCoin indicada + + + + Verify &Message + Verificar &mensaje + + + + Reset all verify message fields + Limpiar todos los campos de la verificación de mensaje + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduzca una dirección CasinoCoin (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Haga clic en "Firmar mensaje" para generar la firma + + + + Enter CasinoCoin signature + Introduzca una firma CasinoCoin + + + + + The entered address is invalid. + La dirección introducida es inválida. + + + + + + + Please check the address and try again. + Verifique la dirección e inténtelo de nuevo. + + + + + The entered address does not refer to a key. + La dirección introducida no corresponde a una clave. + + + + Wallet unlock was cancelled. + Se ha cancelado el desbloqueo del monedero. + + + + Private key for the entered address is not available. + No se dispone de la clave privada para la dirección introducida. + + + + Message signing failed. + Ha fallado la firma del mensaje. + + + + Message signed. + Mensaje firmado. + + + + The signature could not be decoded. + No se puede decodificar la firma. + + + + + Please check the signature and try again. + Compruebe la firma e inténtelo de nuevo. + + + + The signature did not match the message digest. + La firma no coincide con el resumen del mensaje. + + + + Message verification failed. + La verificación del mensaje ha fallado. + + + + Message verified. + Mensaje verificado. + + + + SplashScreen + + + The CasinoCoin developers + Los programadores CasinoCoin + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Abierto hasta %1 bloques - - - + Open until %1 Abierto hasta %1 - - %1/offline? - %1/fuera de linea? + + %1/offline + %1/fuera de línea - + %1/unconfirmed %1/no confirmado - + %1 confirmations %1 confirmaciones - - <b>Status:</b> - <b>Estado:</b> + + Status + Estado + + + + , broadcast through %n node(s) + , transmitir a través de %n nodo, transmitir a través de %n nodos - + + Date + Fecha + + + + Source + Fuente + + + + Generated + Generado + + + + + From + De + + + + + + To + Para + + + + + own address + dirección propia + + + + label + etiqueta + + + + + + + + Credit + Crédito + + + + matures in %n more block(s) + disponible en %n bloque másdisponible en %n bloques más + + + + not accepted + no aceptada + + + + + + + Debit + Débito + + + + Transaction fee + Comisión de transacción + + + + Net amount + Cantidad neta + + + + Message + Mensaje + + + + Comment + Comentario + + + + Transaction ID + Identificador de transacción + + + + Generated coins must mature 120 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. + Las monedas generadas deben esperar 120 bloques antes de que se puedan gastar. Cuando se generó este bloque, se emitió a la red para ser agregado a la cadena de bloques. Si no consigue incorporarse a la cadena, su estado cambiará a "no aceptado" y las monedas no se podrán gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque casi al mismo tiempo que el suyo. + + + + Debug information + Información de depuración + + + + Transaction + Transacción + + + + Inputs + entradas + + + + Amount + Cantidad + + + + true + verdadero + + + + false + falso + + + , has not been successfully broadcast yet - , no ha sido emitido satisfactoriamente todavía + , todavía no se ha sido difundido satisfactoriamente + + + + Open for %n more block(s) + Abrir para %n bloque másAbrir para %n bloques más - - , broadcast through %1 node - , emitido mediante %1 nodo - - - - , broadcast through %1 nodes - , emitido mediante %1 nodos - - - - <b>Date:</b> - <b>Fecha:</b> - - - - <b>Source:</b> Generated<br> - <b>Fuente:</b> Generado<br> - - - - - <b>From:</b> - <b>De:</b> - - - + unknown desconocido - - - - - <b>To:</b> - <b>Para:</b> - - - - (yours, label: - (tuya, etiqueta: - - - - (yours) - (tuya) - - - - - - - <b>Credit:</b> - <b>Crédito:</b> - - - - (%1 matures in %2 more blocks) - (%1 madura en %1 bloques más) - - - - (not accepted) - (no aceptada) - - - - - - <b>Debit:</b> - <b>Débito:</b> - - - - <b>Transaction fee:</b> - <b>Comisión de transacción:</b> - - - - <b>Net amount:</b> - <b>Cantidad total:</b> - - - - Message: - Mensaje: - - - - Comment: - Comentario: - - - - Transaction ID: - Id. de transacción: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Las monedas generadas deben esperar 120 bloques antes de ser gastadas. Cuando has generado este bloque se emitió a la red para ser agregado en la cadena de bloques. Si falla al incluirse en la cadena, cambiará a "no aceptado" y las monedas no se podrán gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque casi al mismo tiempo que el tuyo. - TransactionDescDialog - + Transaction details Detalles de transacción - + This pane shows a detailed description of the transaction Esta ventana muestra información detallada sobre la transacción @@ -1574,967 +1851,1109 @@ Dirección: %4 TransactionTableModel - + Date Fecha - + Type Tipo - + Address Dirección - + Amount Cantidad - - Open for %n block(s) - Abierto por %n bloqueAbierto por %n bloques + + Open for %n more block(s) + Abrir para %n bloque másAbrir para %n bloques más - + Open until %1 Abierto hasta %1 - + Offline (%1 confirmations) - Fuera de linea (%1 confirmaciones) + Fuera de línea (%1 confirmaciones) - + Unconfirmed (%1 of %2 confirmations) No confirmado (%1 de %2 confirmaciones) - + Confirmed (%1 confirmations) Confirmado (%1 confirmaciones) - - Mined balance will be available in %n more blocks - El balance minado estará disponible en %n bloque másEl balance minado estará disponible en %n bloques más + + Mined balance will be available when it matures in %n more block(s) + El saldo recién minado estará disponible cuando venza el plazo en %n bloque másEl saldo recién minado estará disponible cuando venza el plazo en %n bloques más - + This block was not received by any other nodes and will probably not be accepted! - Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado ! + Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado! - + Generated but not accepted Generado pero no aceptado - + Received with Recibido con - + Received from Recibidos de - + Sent to Enviado a - + Payment to yourself Pago propio - + Mined Minado - + (n/a) - (n/a) + (nd) - + Transaction status. Hover over this field to show number of confirmations. Estado de transacción. Pasa el ratón sobre este campo para ver el número de confirmaciones. - + Date and time that the transaction was received. - Fecha y hora de cuando se recibió la transacción. + Fecha y hora en que se recibió la transacción. - + Type of transaction. Tipo de transacción. - + Destination address of transaction. Dirección de destino de la transacción. - + Amount removed from or added to balance. - Cantidad retirada o añadida al balance. + Cantidad retirada o añadida al saldo. TransactionView - - + + All Todo - + Today Hoy - + This week Esta semana - + This month Este mes - + Last month Mes pasado - + This year Este año - + Range... Rango... - + Received with Recibido con - + Sent to Enviado a - + To yourself - A ti mismo + A usted mismo - + Mined Minado - + Other Otra - + Enter address or label to search Introduzca una dirección o etiqueta que buscar - + Min amount Cantidad mínima - + Copy address Copiar dirección - + Copy label Copiar etiqueta - + Copy amount Copiar cuantía - + + Copy transaction ID + Copiar identificador de transacción + + + Edit label Editar etiqueta - + Show transaction details Mostrar detalles de la transacción - + Export Transaction Data Exportar datos de la transacción - + Comma separated file (*.csv) Archivos de columnas separadas por coma (*.csv) - + Confirmed Confirmado - + Date Fecha - + Type Tipo - + Label Etiqueta - + Address Dirección - + Amount Cantidad - + ID ID - + Error exporting Error exportando - + Could not write to file %1. No se pudo escribir en el archivo %1. - + Range: Rango: - + to para - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copia la dirección seleccionada al portapapeles - - - - &Copy Address - &Copiar dirección - - - - Reset all verify message fields - - - - - Clear &All - Limpiar &todo - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Enviando... + + Send Coins + Enviar monedas - WindowOptionsPage + WalletView - - Window - + + &Export + &Exportar - - &Minimize to the tray instead of the taskbar - &Minimiza a la bandeja en vez de la barra de tareas + + Export the data in the current tab to a file + Exportar a un archivo los datos de esta pestaña - - Show only a tray icon after minimizing the window - Muestra solo el icono de sistema cuando se minimice la ventana + + Backup Wallet + Respaldo de monedero - - M&inimize on close - + + Wallet Data (*.dat) + Datos de monedero (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimiza la ventana en lugar de salir de la aplicación.Cuando esta opcion está activa la aplicación solo se puede cerrar seleccionando Salir desde el menú. + + Backup Failed + Ha fallado el respaldo + + + + There was an error trying to save the wallet data to the new location. + Se ha producido un error al intentar guardar los datos del monedero en la nueva ubicación. + + + + Backup Successful + Se ha completado con éxito la copia de respaldo + + + + The wallet data was successfully saved to the new location. + Los datos del monedero se han guardado con éxito en la nueva ubicación. bitcoin-core - - Bitcoin version - Versión de Bitcoin + + CasinoCoin version + Versión de CasinoCoin - + Usage: Uso: - - Send command to -server or bitcoind - Envíar comando a -server o bitcoind + + Send command to -server or casinocoind + Envíar comando a -server o casinocoind - + List commands Muestra comandos - + Get help for a command Recibir ayuda para un comando - + Options: Opciones: - - Specify configuration file (default: bitcoin.conf) - Especifica archivo de configuración (predeterminado: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Especificar archivo de configuración (predeterminado: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Especifica archivo pid (predeterminado: bitcoin.pid) + + Specify pid file (default: casinocoind.pid) + Especificar archivo pid (predeterminado: casinocoin.pid) - - Generate coins - Generar monedas - - - - Don't generate coins - No generar monedas - - - + Specify data directory Especificar directorio para los datos - + Set database cache size in megabytes (default: 25) - Establecer el tamaño del caché de la base de datos en megabytes (por defecto: 25) + Establecer el tamaño de caché de la base de datos en megabytes (predeterminado: 25) - - Set database disk log size in megabytes (default: 100) - Base de datos de conjunto de discos de registro de tamaño en megabytes (por defecto: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Escuchar conexiones en <puerto> (predeterminado: 47950 o testnet: 17950) - - Specify connection timeout (in milliseconds) - Especifica tiempo de espera para conexion (en milisegundos) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Preste atención a las conexiones en <puerto> (por defecto: 8333 o testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) - Mantener en la mayoría de las conexiones <n> a sus compañeros (por defecto: 125) + Mantener como máximo <n> conexiones a pares (predeterminado: 125) - - Connect only to the specified node - Conecta solo al nodo especificado - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Conectar a un nodo para obtener direcciones de pares y desconectar - + Specify your own public address - + Especifique su propia dirección pública - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - Umbral para la desconexión de los compañeros se portan mal (por defecto: 100) + Umbral para la desconexión de pares con mal comportamiento (predeterminado: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - Número de segundos que se mantienen los compañeros se portan mal en volver a conectarse (por defecto: 86400) + Número de segundos en que se evita la reconexión de pares con mal comportamiento (predeterminado: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Máximo por-conexión búfer de recepción, <n>*1000 bytes (por defecto: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Ha ocurrido un error al configurar el puerto RPC %u para escucha en IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Máximo por conexión buffer de envío, <n>*1000 bytes (por defecto: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Escuchar conexiones JSON-RPC en <puerto> (predeterminado: 47970 o testnet:17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Aceptar comandos consola y JSON-RPC - + Run in the background as a daemon and accept commands - Correr como demonio y acepta comandos + Correr como demonio y aceptar comandos - + Use the test network - Usa la red de pruebas + Usar la red de pruebas - - Output extra debugging information - Salida de información de depuración extra + + Accept connections from outside (default: 1 if no -proxy or -connect) + Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, debe establecer un valor rpcpassword en el archivo de configuración: +%s +Se recomienda utilizar la siguiente contraseña aleatoria: +rpcuser=casinocoinrpc +rpcpassword=%s +(no es necesario recordar esta contraseña) +El nombre de usuario y la contraseña DEBEN NO ser iguales. +Si el archivo no existe, créelo con permisos de archivo de solo lectura. +Se recomienda también establecer alertnotify para recibir notificaciones de problemas. +Por ejemplo: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Ha ocurrido un error al configurar el puerto RPC %u para escuchar mediante IPv6. Recurriendo a IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Vincular a la dirección dada y escuchar siempre en ella. Utilice la notación [host]:port para IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + No se puede bloquear el directorio de datos %s. Probablemente CasinoCoin ya se está ejecutando. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + ¡Error: se ha rechazado la transacción! Esto puede ocurrir si ya se han gastado algunas de las monedas del monedero, como ocurriría si hubiera hecho una copia de wallet.dat y se hubieran gastado monedas a partir de la copia, con lo que no se habrían marcado aquí como gastadas. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + ¡Error: Esta transacción requiere una comisión de al menos %s debido a su monto, complejidad, o al uso de fondos recién recibidos! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Ejecutar orden cuando se reciba un aviso relevante (%s en cmd se reemplazará por el mensaje) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Establecer el tamaño máximo de las transacciones de alta prioridad/comisión baja en bytes (predeterminado:27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Esta es una versión de pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería. + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Aviso: ¡-paytxfee tiene un valor muy alto! Esta es la comisión que pagará si envía una transacción. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Aviso: ¡Las transacciones mostradas pueden no ser correctas! Puede necesitar una actualización o bien otros nodos necesitan actualizarse. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Precaución: Por favor, ¡revise que la fecha y hora de su ordenador son correctas! Si su reloj está mal, CasinoCoin no funcionará correctamente. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Aviso: ¡Error al leer wallet.dat! Todas las claves se han leído correctamente, pero podrían faltar o ser incorrectos los datos de transacciones o las entradas de la libreta de direcciones. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Aviso: ¡Recuperados datos de wallet.dat corrupto! El wallet.dat original se ha guardado como wallet.{timestamp}.bak en %s; si hubiera errores en su saldo o transacciones, deberá restaurar una copia de seguridad. + + + + Attempt to recover private keys from a corrupt wallet.dat + Intento de recuperar claves privadas de un wallet.dat corrupto + + + + Block creation options: + Opciones de creación de bloques: + + + + Connect only to the specified node(s) + Conectar sólo a los nodos (o nodo) especificados + + + + Corrupted block database detected + Corrupción de base de datos de bloques detectada. + + + + Discover own IP address (default: 1 when listening and no -externalip) + Descubrir dirección IP propia (predeterminado: 1 al escuchar sin -externalip) + + + + Do you want to rebuild the block database now? + ¿Quieres reconstruir la base de datos de bloques ahora? + + + + Error initializing block database + Error al inicializar la base de datos de bloques + + + + Error initializing wallet database environment %s! + Error al inicializar el entorno de la base de datos del monedero %s + + + + Error loading block database + Error cargando base de datos de bloques + + + + Error opening block database + Error al abrir base de datos de bloques. + + + + Error: Disk space is low! + Error: ¡Espacio en disco bajo! + + + + Error: Wallet locked, unable to create transaction! + Error: ¡El monedero está bloqueado; no se puede crear la transacción! + + + + Error: system error: + Error: error de sistema: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Ha fallado la escucha en todos los puertos. Use -listen=0 si desea esto. + + + + Failed to read block info + No se ha podido leer la información de bloque + + + + Failed to read block + No se ha podido leer el bloque + + + + Failed to sync block index + No se ha podido sincronizar el índice de bloques + + + + Failed to write block index + No se ha podido escribir en el índice de bloques + + + + Failed to write block info + No se ha podido escribir la información de bloques + + + + Failed to write block + No se ha podido escribir el bloque + + + + Failed to write file info + No se ha podido escribir la información de archivo + + + + Failed to write to coin database + No se ha podido escribir en la base de datos de monedas + + + + Failed to write transaction index + No se ha podido escribir en el índice de transacciones + + + + Failed to write undo data + No se han podido escribir los datos de deshacer + + + + Find peers using DNS lookup (default: 1 unless -connect) + Encontrar pares mediante búsqueda de DNS (predeterminado: 1 salvo con -connect) + + + + Generate coins (default: 0) + Generar monedas (por defecto: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Cuántos bloques comprobar al iniciar (predeterminado: 288, 0 = todos) + + + + How thorough the block verification is (0-4, default: 3) + Como es de exhaustiva la verificación de bloques (0-4, por defecto 3) + + + + Not enough file descriptors available. + No hay suficientes descriptores de archivo disponibles. + + + + Rebuild block chain index from current blk000??.dat files + Reconstruir el índice de la cadena de bloques a partir de los archivos blk000??.dat actuales + + + + Set the number of threads to service RPC calls (default: 4) + Establecer el número de hilos para atender las llamadas RPC (predeterminado: 4) + + + + Verifying blocks... + Verificando bloques... + + + + Verifying wallet... + Verificando monedero... + + + + Imports blocks from external blk000??.dat file + Importa los bloques desde un archivo blk000??.dat externo + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Configura el número de hilos para el script de verificación (hasta 16, 0 = auto, <0 = leave that many cores free, por fecto: 0) + + + + Information + Información + + + + Invalid -tor address: '%s' + Dirección -tor inválida: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Inválido por el monto -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Inválido por el monto -mintxfee=<amount>: '%s' + + + + Maintain a full transaction index (default: 0) + Mantener índice de transacciones completo (predeterminado: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Búfer de recepción máximo por conexión, <n>*1000 bytes (predeterminado: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Búfer de recepción máximo por conexión, , <n>*1000 bytes (predeterminado: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Aceptar solamente cadena de bloques que concuerde con los puntos de control internos (predeterminado: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Conectarse solo a nodos de la red <net> (IPv4, IPv6 o Tor) + + + + Output extra debugging information. Implies all other -debug* options + Mostrar información de depuración adicional. Implica todos los demás opciones -debug* + + + + Output extra network debugging information + Mostrar información de depuración adicional + + + Prepend debug output with timestamp - Anteponer la salida de depuración, con indicación de la hora + Anteponer marca temporal a la información de depuración - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opciones SSL: (ver la CasinoCoin Wiki para instrucciones de configuración SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Elija la versión del proxy socks a usar (4-5, predeterminado: 5) + + + Send trace/debug info to console instead of debug.log file - Enviar rastrear/debug info a la consola en lugar de debug.log archivo + Enviar información de trazas/depuración a la consola en lugar de al archivo debug.log - + Send trace/debug info to debugger - Enviar rastrear / debug info al depurador + Enviar información de trazas/depuración al depurador - + + Set maximum block size in bytes (default: 250000) + Establecer tamaño máximo de bloque en bytes (predeterminado: 250000) + + + + Set minimum block size in bytes (default: 0) + Establecer tamaño mínimo de bloque en bytes (predeterminado: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Reducir el archivo debug.log al iniciar el cliente (predeterminado: 1 sin -debug) + + + + Signing transaction failed + Transacción falló + + + + Specify connection timeout in milliseconds (default: 5000) + Especificar el tiempo máximo de conexión en milisegundos (predeterminado: 5000) + + + + System error: + Error de sistema: + + + + Transaction amount too small + Monto de la transacción muy pequeño + + + + Transaction amounts must be positive + Montos de transacciones deben ser positivos + + + + Transaction too large + Transacción demasiado grande + + + + Use UPnP to map the listening port (default: 0) + Usar UPnP para asignar el puerto de escucha (predeterminado: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Usar UPnP para asignar el puerto de escucha (predeterminado: 1 al escuchar) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Utilizar proxy para conectar a Tor servicios ocultos (predeterminado: igual que -proxy) + + + Username for JSON-RPC connections - Usuario para las conexiones JSON-RPC + Nombre de usuario para las conexiones JSON-RPC - + + Warning + Aviso + + + + Warning: This version is obsolete, upgrade required! + Aviso: Esta versión es obsoleta, actualización necesaria! + + + + You need to rebuild the databases using -reindex to change -txindex + Necesita reconstruir las bases de datos con la opción -reindex para modificar -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat corrupto. Ha fallado la recuperación. + + + Password for JSON-RPC connections Contraseña para las conexiones JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - Escucha conexiones JSON-RPC en el puerto <port> (predeterminado: 8332) - - - - + Allow JSON-RPC connections from specified IP address - Permite conexiones JSON-RPC desde la dirección IP especificada + Permitir conexiones JSON-RPC desde la dirección IP especificada - + Send commands to node running on <ip> (default: 127.0.0.1) - Envía comando al nodo situado en <ip> (predeterminado: 127.0.0.1) + Enviar comando al nodo situado en <ip> (predeterminado: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque) - + Upgrade wallet to latest format Actualizar el monedero al último formato - + Set key pool size to <n> (default: 100) - Ajusta el número de claves en reserva <n> (predeterminado: 100) + Ajustar el número de claves en reserva <n> (predeterminado: 100) - + Rescan the block chain for missing wallet transactions Volver a examinar la cadena de bloques en busca de transacciones del monedero perdidas - - How many blocks to check at startup (default: 2500, 0 = all) - Cuántos bloques para comprobar en el arranque (por defecto: 2500, 0 = todos) - - - - How thorough the block verification is (0-6, default: 1) - Cómo completa la verificación del bloque es (0-6, por defecto: 1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opciones SSL: (ver la Bitcoin Wiki para instrucciones de configuración SSL) - - - - + Use OpenSSL (https) for JSON-RPC connections - Usa OpenSSL (https) para las conexiones JSON-RPC + Usar OpenSSL (https) para las conexiones JSON-RPC - + Server certificate file (default: server.cert) - Certificado del servidor (Predeterminado: server.cert) + Certificado del servidor (predeterminado: server.cert) - + Server private key (default: server.pem) - Clave privada del servidor (Predeterminado: server.pem) + Clave privada del servidor (predeterminado: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Cifrados aceptados (Predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Cifrados aceptados (predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Este mensaje de ayuda - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - No se puede obtener permiso de trabajo en la carpeta de datos %s. Probablemente Bitcoin ya se está ejecutando. - - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + No es posible conectar con %s en este sistema (bind ha dado el error %d, %s) - + Connect through socks proxy - + Conectar mediante proxy socks - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Permitir búsquedas DNS para -addnode, -seednode y -connect - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Cargando direcciones... - - Error loading blkindex.dat - Error al cargar blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Error al cargar wallet.dat: el monedero está dañado - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Error al cargar wallet.dat: El monedero requiere una versión más reciente de Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Error al cargar wallet.dat: El monedero requiere una versión más reciente de CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - El monedero ha necesitado ser reescrito. Reinicie Bitcoin para completar el proceso + + Wallet needed to be rewritten: restart CasinoCoin to complete + El monedero ha necesitado ser reescrito. Reinicie CasinoCoin para completar el proceso - + Error loading wallet.dat Error al cargar wallet.dat - + Invalid -proxy address: '%s' - + Dirección -proxy inválida: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + La red especificada en -onlynet '%s' es desconocida - + Unknown -socks proxy version requested: %i - + Solicitada versión de proxy -socks desconocida: %i - + Cannot resolve -bind address: '%s' - + No se puede resolver la dirección de -bind: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + No se puede resolver la dirección de -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Cantidad inválida para -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Error: monedero bloqueado. Bitcoin es incapaz de crear las transacciones - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Error: esta transacción está sujeta a una tarifa de %s, bien por su cantidad, complejidad, o por el uso de fondos recientemente recibidos - - - - Error: Transaction creation failed - Error: no se ha podido crear la transacción - - - - Sending... - Enviando... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Error: la transacción fue rechazada. Esto puede pasar si alguna de las monedas ya estaba gastada o si ha usado una copia de wallet.dat y las monedas se gastaron en la copia pero no se han marcado como gastadas aquí. - - - + Invalid amount Cuantía no válida - + Insufficient funds Fondos insuficientes - + Loading block index... Cargando el índice de bloques... - + Add a node to connect to and attempt to keep the connection open - Añadir un nodo para conectarse y tratar de mantener la conexión abierta + Añadir un nodo al que conectarse y tratar de mantener la conexión abierta - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + No es posible conectar con %s en este sistema. Probablemente CasinoCoin ya está ejecutándose. - - Find peers using internet relay chat (default: 0) - Encontrar los pares utilizando Internet Relay Chat (por defecto: 0) - - - - Accept connections from outside (default: 1) - Aceptar conexiones desde el exterior (por defecto: 1) - - - - Find peers using DNS lookup (default: 1) - Encontrar compañeros con búsqueda de DNS (por defecto: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Use Universal Plug and Play para asignar el puerto de escucha (por defecto: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Use Universal Plug and Play para asignar el puerto de escucha (por defecto: 0) - - - + Fee per KB to add to transactions you send Tarifa por KB que añadir a las transacciones que envíe - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Cargando monedero... - + Cannot downgrade wallet No se puede rebajar el monedero - - Cannot initialize keypool - No se puede inicializar grupo de teclas - - - + Cannot write default address - No se puede escribir la dirección por defecto + No se puede escribir la dirección predeterminada - + Rescanning... - Rescaneando... + Reexplorando... - + Done loading Generado pero no aceptado - + To use the %s option Para utilizar la opción %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, tiene que establecer rpcpassword en el archivo de configuración: ⏎ -%s ⏎ -Se recomienda utilizar la siguiente contraseña aleatoria: ⏎ -rpcuser = bitcoinrpc ⏎ -rpcpassword =%s ⏎ -(no es necesario para recordar esta contraseña) ⏎ -Si el archivo no existe se crea con los permisos de lectura y escritura solamente del propietario. ⏎ - - - + Error Error - - An error occured while setting up the RPC port %i for listening: %s - Ha ocurrido un error al instalar el puerto RPC %i para escuchar: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. Tiene que establecer rpcpassword=<contraseña> en el fichero de configuración: ⏎ %s ⏎ -Si el archivo no existe, se crea con permisos de propietario de lectura de sólo archivos. - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Precaución: revise por favor que la fecha y hora de su sistema son correctas. Si el reloj está mal Bitcoin no funcionará correctamente. +Si el archivo no existe, créelo con permiso de lectura solamente del propietario. \ 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 5a11ee2..75e405e 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -3,122 +3,163 @@ AboutDialog - - About Bitcoin - Sobre Bitcoin + + About CasinoCoin + Sobre CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> - versión + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> - versión - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 desarrolladores Bitcoin - + Este es un software experimental. -Distribuído bajo la licencia de software MIT/X11, vease el archivo adjunto licence.txt o http://www.opensource.org/licenses/mit-license.php. +Distribuido bajo la licencia MIT/X11, vea el archivo adjunto +COPYING o http://www.opensource.org/licenses/mit-license.php. -Este producto include software desarrollado por el proyecto OpenSSL para ser usado en el OpenSSL Toolkit (http://www.openssl.org/) y software criptográfico escrito por Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. +Este producto incluye software desarrollado por OpenSSL Project para su uso en +el OpenSSL Toolkit (http://www.openssl.org/), software criptográfico escrito por +Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. + + + + Copyright + + + + + The CasinoCoin developers + AddressBookPage - + Address Book Guia de direcciones - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Estas son tus direcciones Bitcoin para recibir pagos. Puedes utilizar una diferente por cada persona emisora para saber quien te está pagando. - - - + Double-click to edit address or label Haz doble clic para editar una dirección o etiqueta - + Create a new address Crea una nueva dirección - + Copy the currently selected address to the system clipboard Copia la dirección seleccionada al portapapeles - + &New Address - + &Nueva dirección - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Estas son tus direcciones CasinoCoin para recibir pagos. Puedes utilizar una diferente por cada persona emisora para saber quien te está pagando. + + + &Copy Address - + &Copia dirección - + Show &QR Code Mostrar Código &QR - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address Firmar un mensaje para provar que usted es dueño de esta dirección - - &Sign Message + + Sign &Message Firmar Mensaje - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Borra la dirección seleccionada de la lista. Solo las direcciónes de envio se pueden borrar. + + Delete the currently selected address from the list + - + + Export the data in the current tab to a file + Exportar los datos de la pestaña actual a un archivo + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete &Borrar - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Copia &etiqueta - + &Edit + &Editar + + + + Send &Coins - + Export Address Book Data Exporta datos de la guia de direcciones - + Comma separated file (*.csv) Archivos separados por coma (*.csv) - + Error exporting Exportar errores - + Could not write to file %1. No se pudo escribir al archivo %1. @@ -126,17 +167,17 @@ Este producto include software desarrollado por el proyecto OpenSSL para ser usa AddressTableModel - + Label Etiqueta - + Address Dirección - + (no label) (sin etiqueta) @@ -144,432 +185,460 @@ Este producto include software desarrollado por el proyecto OpenSSL para ser usa AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase Introduce contraseña actual - + New passphrase Nueva contraseña - + Repeat new passphrase Repite nueva contraseña: - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Introduce la nueva contraseña para la billetera.<br/>Por favor utiliza un contraseña <b>de 10 o mas caracteres aleatorios</b>, u <b>ocho o mas palabras</b>. - + Encrypt wallet Codificar billetera - + This operation needs your wallet passphrase to unlock the wallet. Esta operación necesita la contraseña para desbloquear la billetera. - + Unlock wallet Desbloquea billetera - + This operation needs your wallet passphrase to decrypt the wallet. Esta operación necesita la contraseña para decodificar la billetara. - + Decrypt wallet Decodificar cartera - + Change passphrase Cambia contraseña - + Enter the old and new passphrase to the wallet. Introduce la contraseña anterior y la nueva de cartera - + Confirm wallet encryption Confirma la codificación de cartera - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ATENCIÓN: ¡Si codificas tu billetera y pierdes la contraseña perderás <b>TODOS TUS BITCOINS</b>!" -¿Seguro que quieres seguir codificando la billetera? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Atención: ¡Si codificas tu billetera y pierdes la contraseña perderás <b>TODOS TUS CASINOCOINS</b>! - - + + Are you sure you wish to encrypt your wallet? + ¿Seguro que quieres seguir codificando la billetera? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + Precaucion: Mayúsculas Activadas + + + + Wallet encrypted Billetera codificada - - Bitcoin 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. - Bitcoin se cerrará para finalizar el proceso de encriptación. Recuerde que encriptar su billetera no protegera completatamente sus bitcoins de ser robados por malware que infecte su computador + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin se cerrará para finalizar el proceso de encriptación. Recuerde que encriptar su billetera no protegera completatamente sus casinocoins de ser robados por malware que infecte su computador - - - Warning: The Caps Lock key is on. - Precaucion: Mayúsculas Activadas - - - - - - + + + + Wallet encryption failed Falló la codificación de la billetera - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. La codificación de la billetera falló debido a un error interno. Tu billetera no ha sido codificada. - - + + The supplied passphrases do not match. Las contraseñas no coinciden. - + Wallet unlock failed Ha fallado el desbloqueo de la billetera - - - + + + The passphrase entered for the wallet decryption was incorrect. La contraseña introducida para decodificar la billetera es incorrecta. - + Wallet decryption failed Ha fallado la decodificación de la billetera - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. La contraseña de billetera ha sido cambiada con éxito. BitcoinGUI - - Bitcoin Wallet - Billetera Bitcoin - - - + Sign &message... - + Firmar &Mensaje... - - Show/Hide &Bitcoin - Mostrar/Ocultar &Bitcoin - - - + Synchronizing with network... Sincronizando con la red... - + &Overview &Vista general - + Show general overview of wallet Muestra una vista general de la billetera - + &Transactions &Transacciónes - + Browse transaction history Explora el historial de transacciónes - - &Address Book - &Guia de direcciónes - - - + Edit the list of stored addresses and labels Edita la lista de direcciones y etiquetas almacenadas - - &Receive coins - &Recibir monedas - - - + Show the list of addresses for receiving payments Muestra la lista de direcciónes utilizadas para recibir pagos - - &Send coins - &Envíar monedas - - - - Prove you control an address - Suministre dirección de control - - - + E&xit &Salir - + Quit application Salir del programa - - &About %1 - S&obre %1 + + Show information about CasinoCoin + Muestra información acerca de CasinoCoin - - Show information about Bitcoin - Muestra información acerca de Bitcoin - - - + About &Qt Acerca de - + Show information about Qt Mostrar Información sobre QT - + &Options... &Opciones - + &Encrypt Wallet... - + &Codificar la billetera... - + &Backup Wallet... - + &Respaldar billetera... - + &Change Passphrase... - - - - - ~%n block(s) remaining - %n bloque restante%n bloques restantes + &Cambiar la contraseña... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Descargados %1 de %2 bloques del historial de transacciones (%3% hecho). - - - - &Export... - &Exportar... - - - - Send coins to a Bitcoin address + + Importing blocks from disk... - - Modify configuration options for Bitcoin + + Reindexing blocks on disk... - - Show or hide the Bitcoin window - Mostrar u ocultar la ventana de Bitcoin + + Send coins to a CasinoCoin address + Enviar monedas a una dirección casinocoin - - Export the data in the current tab to a file - Exportar los datos de la pestaña actual a un archivo + + Modify configuration options for CasinoCoin + Modifica las opciones de configuración de casinocoin - - Encrypt or decrypt wallet - Codificar o decodificar la billetera - - - + Backup wallet to another location Respaldar billetera en otra ubicación - + Change the passphrase used for wallet encryption Cambiar la contraseña utilizada para la codificación de la billetera - + &Debug window - + Open debugging and diagnostic console - + &Verify message... - - Verify a message signature + + + CasinoCoin + CasinoCoin + + + + Wallet + Cartera + + + + &Send - + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + &Sobre CasinoCoin + + + + &Show / Hide + &Mostrar/Ocultar + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Archivo - + &Settings &Configuración - + &Help &Ayuda - + Tabs toolbar Barra de pestañas - - Actions toolbar - Barra de acciónes - - - - + + [testnet] [red-de-pruebas] - - - Bitcoin client - Cliente Bitcoin + + CasinoCoin client + Cliente CasinoCoin - - %n active connection(s) to Bitcoin network - %n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin + + %n active connection(s) to CasinoCoin network + %n conexión activa hacia la red CasinoCoin%n conexiones activas hacia la red CasinoCoin - - Downloaded %1 blocks of transaction history. - Descargado %1 bloques del historial de transacciones. - - - - %n second(s) ago - Hace %n segundoHace %n segundos - - - - %n minute(s) ago - Hace %n minutoHace %n minutos - - - - %n hour(s) ago - Hace %n horaHace %n horas - - - - %n day(s) ago - Hace %n díaHace %n días + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Actualizado - + Catching up... Recuperando... - - Last received block was generated %1. - El ultimo bloque recibido fue generado %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Esta transacción supera el límite. Puedes seguir enviandola incluyendo una comisión de %s que se va a repartir entre los nodos que procesan su transacción y ayudan a mantener la red. ¿Quieres seguir con la transacción? - - - + Confirm transaction fee - + Sent transaction Transacción enviada - + Incoming transaction Transacción entrante - + Date: %1 Amount: %2 Type: %3 @@ -581,539 +650,486 @@ Tipo: %3 Dirección: %4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> La billetera esta <b>codificada</b> y actualmente <b>desbloqueda</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> La billetera esta <b>codificada</b> y actualmente <b>bloqueda</b> - - Backup Wallet - Respaldar billetera - - - - Wallet Data (*.dat) - Datos de billetera (*.dat) - - - - Backup Failed - Ha fallado el respaldo - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - Mostrado - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Elige la subdivisión por defecto para mostrar cantidaded en la interfaz cuando se envien monedas - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address Editar dirección - + &Label &Etiqueta - + The label associated with this address book entry La etiqueta asociada con esta entrada de la libreta de direcciones - + &Address &Dirección - + The address associated with this address book entry. This can only be modified for sending addresses. La dirección asociada con esta entrada en la libreta de direcciones. Solo puede ser modificada para direcciónes de envío. - + New receiving address Nueva dirección para recibir - + New sending address Nueva dirección para enviar - + Edit receiving address Editar dirección de recepción - + Edit sending address Editar dirección de envio - + The entered address "%1" is already in the address book. La dirección introducida "%1" ya esta guardada en la libreta de direcciones. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + La dirección introducida "%1" no es una dirección CasinoCoin valida. - + Could not unlock wallet. No se pudo desbloquear la billetera. - + New key generation failed. La generación de nueva clave falló. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + versión - + Usage: Uso: - - options + + command-line options - + UI options - + UI opciones - + Set language, for example "de_DE" (default: system locale) - + Start minimized Arranca minimizado - + Show splash screen on startup (default: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Opciones + + + + &Main + &Principal + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Comisión de &transacciónes - - Main - Principal + + Automatically start CasinoCoin after logging in to the system. + Inicia CasinoCoin automáticamente despues de encender el computador - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Comisión opcional por kB que ayuda a asegurar que sus transacciones son procesadas rápidamente. La mayoria de transacciones son de 1 KB. Se recomienda comisión de 0.01 + + &Start CasinoCoin on system login + &Inicia CasinoCoin al iniciar el sistema - - &Start Bitcoin on system login + + Reset all client options to default. - - Automatically start Bitcoin after logging in to the system + + &Reset Options - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message + + &Network - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Abre automáticamente el puerto del cliente CasinoCoin en el router. Esto funciona solo cuando tu router es compatible con UPnP y está habilitado. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - La dirección con la que codificar el mensaje (ej: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Elije dirección de la guia - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Pega dirección desde portapapeles - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Escriba el mensaje que desea firmar - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Click en "Firmar Mensage" para conseguir firma - - - - Sign a message to prove you own this address - Firmar un mensjage para probar que usted es dueño de esta dirección - - - - &Sign Message - & Firmar Mensaje - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduce una dirección Bitcoin (ej. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Error al firmar - - - - %1 is not a valid address. - %1 no es una dirección válida. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Llave privada para %q no esta disponible. - - - - Sign failed - Falló Firma - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Direcciona el puerto usando &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Abre automáticamente el puerto del cliente Bitcoin en el router. Esto funciona solo cuando tu router es compatible con UPnP y está habilitado. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Conecta a la red CasinoCoin a través de un proxy SOCKS (ej. cuando te conectas por la red Tor) - - &Connect through SOCKS4 proxy: - &Conecta a traves de un proxy SOCKS4: + + &Connect through SOCKS proxy: + &Conecta a traves de un proxy SOCKS: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Conecta a la red Bitcoin a través de un proxy SOCKS4 (ej. cuando te conectas por la red Tor) - - - + Proxy &IP: - + &IP Proxy: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Dirección IP del servidor proxy (ej. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Puerto del servidor proxy (ej. 1234) + + &Port: + &Puerto: - - - OptionsDialog - - Options - Opciones + + Port of the proxy (e.g. 9050) + Puerto del servidor proxy (ej. 9050) + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + Muestra solo un ícono en la bandeja después de minimizar la ventana + + + + &Minimize to the tray instead of the taskbar + &Minimiza a la bandeja en vez de la barra de tareas + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimiza la ventana en lugar de salir del programa cuando la ventana se cierra. Cuando esta opción esta activa el programa solo se puede cerrar seleccionando Salir desde el menu. + + + + M&inimize on close + M&inimiza a la bandeja al cerrar + + + + &Display + &Mostrado + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + &Unidad en la que mostrar cantitades: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Elige la subdivisión por defecto para mostrar cantidaded en la interfaz cuando se envien monedas + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + &Muestra direcciones en el listado de transaccioines + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Atención + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + OverviewPage - + Form Formulario - - - 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - + Balance: Saldo: - - Number of transactions: - Numero de transacciones: - - - + Unconfirmed: No confirmados: - + Wallet + Cartera + + + + Immature: - + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> <b>Transacciones recientes</b> - + Your current balance Tu saldo actual - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Total de transacciones que no han sido confirmadas aun, y que no cuentan para el saldo actual. - - Total number of transactions in wallet - Número total de transacciones en la billetera - - - - + + out of sync + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + QRCodeDialog - + QR Code Dialog - - QR Code - Código QR - - - + Request Payment Solicitar Pago - + Amount: Cantidad: - - BTC - BTC - - - + Label: Etiqueta - + Message: Mensaje: - + &Save As... &Guardar Como... - + Error encoding URI into QR Code. - + + The entered amount is invalid, please check. + + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + PNG Images (*.png) Imágenes PNG (*.png) @@ -1121,125 +1137,146 @@ Dirección: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Number of connections - + On testnet - + Block chain - + Current number of blocks - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1247,327 +1284,566 @@ Dirección: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Enviar monedas - + Send to multiple recipients at once Enviar a múltiples destinatarios - - &Add Recipient - + + Add &Recipient + &Agrega destinatario - + Remove all transaction fields Remover todos los campos de la transacción - + Clear &All - + &Borra todos - + Balance: Balance: - + 123.456 BTC 123.456 BTC - + Confirm the send action Confirma el envio - - &Send + + S&end &Envía - + <b>%1</b> to %2 (%3) <b>%1</b> to %2 (%3) - + Confirm send coins Confirmar el envio de monedas - + Are you sure you want to send %1? Estas seguro que quieres enviar %1? - + and y - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. La dirección de destinatarion no es valida, comprueba otra vez. - + The amount to pay must be larger than 0. La cantidad por pagar tiene que ser mayor 0. - + The amount exceeds your balance. - + La cantidad sobrepasa tu saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + El total sobrepasa tu saldo cuando se incluyen %1 como tasa de envio. - + Duplicate address found, can only send to each address once per send operation. + Tienes una dirección duplicada, solo puedes enviar a direcciónes individuales de una sola vez. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Error: La transacción fue rechazada. Esto puede haber ocurrido si alguna de las monedas ya estaba gastada o si ha usado una copia de wallet.dat y las monedas se gastaron en la copia pero no se han marcado como gastadas aqui. SendCoinsEntry - + Form Envio - + A&mount: Cantidad: - + Pay &To: &Pagar a: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Introduce una etiqueta a esta dirección para añadirla a tu guia - + &Label: &Etiqueta: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - La dirección donde enviar el pago (ej. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Elije dirección de la guia - + Alt+A Alt+A - + Paste address from clipboard Pega dirección desde portapapeles - + Alt+P Alt+P - + Remove this recipient Elimina destinatario - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduce una dirección Bitcoin (ej. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduce una dirección CasinoCoin (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Firmar Mensaje + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduce una dirección CasinoCoin (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Elije dirección de la guia + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Pega dirección desde portapapeles + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Escriba el mensaje que desea firmar + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + Firmar un mensjage para probar que usted es dueño de esta dirección + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + &Borra todos + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduce una dirección CasinoCoin (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduce una dirección CasinoCoin (ej. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Click en "Firmar Mensage" para conseguir firma + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [red-de-pruebas] TransactionDesc - - Open for %1 blocks - Abierto hasta %1 bloques - - - + Open until %1 Abierto hasta %1 - - %1/offline? - %1/fuera de linea? + + %1/offline + %1/fuera de linea - + %1/unconfirmed %1/no confirmado - + %1 confirmations %1 confirmaciónes - - <b>Status:</b> - <b>Estado:</b> + + Status + Estado + + + + , broadcast through %n node(s) + - + + Date + Fecha + + + + Source + + + + + Generated + Generado + + + + + From + De + + + + + + To + + + + + + own address + + + + + label + etiqueta + + + + + + + + Credit + Credito + + + + matures in %n more block(s) + + + + + not accepted + no aceptada + + + + + + + Debit + Debito + + + + Transaction fee + Comisión transacción + + + + Net amount + Cantidad total + + + + Message + Mensaje + + + + Comment + Comentario + + + + Transaction ID + ID de Transacción + + + + Generated coins must mature 120 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. + Las monedas generadas deben esperar 120 bloques antes de ser gastadas. Cuando has generado este bloque se emitió a la red para ser agregado en la cadena de bloques. Si falla al incluirse en la cadena, cambiará a "no aceptado" y las monedas no se podrán gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque casi al mismo tiempo que el tuyo. + + + + Debug information + + + + + Transaction + Transacción + + + + Inputs + + + + + Amount + Cantidad + + + + true + + + + + false + + + + , has not been successfully broadcast yet , no ha sido emitido satisfactoriamente todavía - - - , broadcast through %1 node - , emitido mediante %1 nodo + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , emitido mediante %1 nodos - - - - <b>Date:</b> - <b>Fecha:</b> - - - - <b>Source:</b> Generated<br> - <b>Fuente:</b> Generado<br> - - - - - <b>From:</b> - <b>De:</b> - - - + unknown desconocido - - - - - <b>To:</b> - <b>Para:</b> - - - - (yours, label: - (tuya, etiqueta: - - - - (yours) - (tuya) - - - - - - - <b>Credit:</b> - <b>Crédito:</b> - - - - (%1 matures in %2 more blocks) - (%1 madura en %2 bloques mas) - - - - (not accepted) - (no aceptada) - - - - - - <b>Debit:</b> - <b>Débito:</b> - - - - <b>Transaction fee:</b> - <b>Comisión transacción:</b> - - - - <b>Net amount:</b> - <b>Cantidad total:</b> - - - - Message: - Mensaje: - - - - Comment: - Comentario: - - - - Transaction ID: - ID de Transacción: - - - - Generated coins must wait 8 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Las monedas generadas deben esperar 8 bloques antes de ser gastadas. Cuando has generado este bloque se emitió a la red para ser agregado en la cadena de bloques. Si falla al incluirse en la cadena, cambiará a "no aceptado" y las monedas no se podrán gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque casi al mismo tiempo que el tuyo. - TransactionDescDialog - + Transaction details Detalles de transacción - + This pane shows a detailed description of the transaction Esta ventana muestra información detallada sobre la transacción @@ -1575,117 +1851,117 @@ Dirección: %4 TransactionTableModel - + Date Fecha - + Type Tipo - + Address Dirección - + Amount Cantidad - - Open for %n block(s) - Abierto por %n bloqueAbierto por %n bloques + + Open for %n more block(s) + - + Open until %1 Abierto hasta %1 - + Offline (%1 confirmations) Fuera de linea (%1 confirmaciónes) - + Unconfirmed (%1 of %2 confirmations) No confirmado (%1 de %2 confirmaciónes) - + Confirmed (%1 confirmations) Confirmado (%1 confirmaciones) - - Mined balance will be available in %n more blocks - El balance minado estará disponible en %n bloque masEl balance minado estará disponible en %n bloques mas + + Mined balance will be available when it matures in %n more block(s) + - + This block was not received by any other nodes and will probably not be accepted! Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado ! - + Generated but not accepted Generado pero no acceptado - + Received with Recibido con - + Received from Recibido de - + Sent to Enviado a - + Payment to yourself Pagar a usted mismo - + Mined Minado - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. Estado de transacción. Pasa el raton sobre este campo para ver el numero de confirmaciónes. - + Date and time that the transaction was received. Fecha y hora cuando se recibió la transaccion - + Type of transaction. Tipo de transacción. - + Destination address of transaction. Dirección de destino para la transacción - + Amount removed from or added to balance. Cantidad restada o añadida al balance @@ -1693,846 +1969,984 @@ Dirección: %4 TransactionView - - + + All Todo - + Today Hoy - + This week Esta semana - + This month Esta mes - + Last month Mes pasado - + This year Este año - + Range... Rango... - + Received with Recibido con - + Sent to Enviado a - + To yourself A ti mismo - + Mined Minado - + Other Otra - + Enter address or label to search Introduce una dirección o etiqueta para buscar - + Min amount Cantidad minima - + Copy address Copia dirección - + Copy label Copia etiqueta - + Copy amount Copiar Cantidad - + + Copy transaction ID + + + + Edit label Edita etiqueta - + Show transaction details - + Export Transaction Data Exportar datos de transacción - + Comma separated file (*.csv) Archivos separados por coma (*.csv) - + Confirmed Confirmado - + Date Fecha - + Type Tipo - + Label Etiqueta - + Address Dirección - + Amount Cantidad - + ID ID - + Error exporting Error exportando - + Could not write to file %1. No se pudo escribir en el archivo %1. - + Range: Rango: - + to para - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copiar la dirección seleccionada al portapapeles - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Enviando... + + Send Coins + Enviar monedas - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Minimiza a la bandeja en vez de la barra de tareas + + Export the data in the current tab to a file + Exportar los datos de la pestaña actual a un archivo - - Show only a tray icon after minimizing the window - Muestra solo un ícono en la bandeja después de minimizar la ventana - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimiza la ventana en lugar de salir del programa cuando la ventana se cierra. Cuando esta opción esta activa el programa solo se puede cerrar seleccionando Salir desde el menu. + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - Versión Bitcoin + + CasinoCoin version + Versión CasinoCoin - + Usage: Uso: - - Send command to -server or bitcoind - Envia comando a bitcoin lanzado con -server u bitcoind + + Send command to -server or casinocoind + Envia comando a casinocoin lanzado con -server u casinocoind - + List commands Muestra comandos - + Get help for a command Recibir ayuda para un comando - + Options: Opciones: - - Specify configuration file (default: bitcoin.conf) - Especifica archivo de configuración (predeterminado: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Especifica archivo de configuración (predeterminado: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Especifica archivo pid (predeterminado: bitcoin.pid) + + Specify pid file (default: casinocoind.pid) + Especifica archivo pid (predeterminado: casinocoin.pid) - - Generate coins - Genera monedas - - - - - Don't generate coins - No generar monedas - - - - + Specify data directory Especifica directorio para los datos - + Set database cache size in megabytes (default: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Escuchar por conecciones en <puerto> (Por defecto: 47950 o red de prueba: 17950) - - Specify connection timeout (in milliseconds) - Especifica tiempo de espera para conexion (en milisegundos) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Escuchar por conecciones en <puerto> (Por defecto: 8333 o red de prueba: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Mantener al menos <n> conecciones por cliente (por defecto: 125) - - Connect only to the specified node - Conecta solo al nodo especificado - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Umbral de desconección de clientes con mal comportamiento (por defecto: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Escucha conexiones JSON-RPC en el puerto <port> (predeterminado: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Aceptar comandos consola y JSON-RPC - + Run in the background as a daemon and accept commands Correr como demonio y acepta comandos - + Use the test network Usa la red de pruebas - - Output extra debugging information - Adjuntar informacion extra de depuracion + + Accept connections from outside (default: 1 if no -proxy or -connect) + - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Precaución: -paytxfee es muy alta. Esta es la comisión que pagarás si envias una transacción. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Precaución: Por favor revise que la fecha y hora de tu ordenador son correctas. Si tu reloj está mal configurado CasinoCoin no funcionará correctamente. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + Conecta solo al nodo especificado + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Dirección -tor invalida: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + Adjuntar informacion extra de depuracion. Implies all other -debug* options + + + + Output extra network debugging information + + + + Prepend debug output with timestamp Anteponer salida de depuracion con marca de tiempo - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opciones SSL: (ver la CasinoCoin Wiki para instrucciones de configuración SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + Send trace/debug info to console instead of debug.log file Enviar informacion de seguimiento a la consola en vez del archivo debug.log - + Send trace/debug info to debugger Enviar informacion de seguimiento al depurador - + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Especifica tiempo de espera para conexion en milisegundos (predeterminado: 5000) + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Intenta usar UPnP para mapear el puerto de escucha (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Intenta usar UPnP para mapear el puerto de escucha (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + Username for JSON-RPC connections Usuario para las conexiones JSON-RPC - + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + Password for JSON-RPC connections Contraseña para las conexiones JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - Escucha conexiones JSON-RPC en el puerto <port> (predeterminado: 8332) - - - - + Allow JSON-RPC connections from specified IP address Permite conexiones JSON-RPC desde la dirección IP especificada - + Send commands to node running on <ip> (default: 127.0.0.1) Envia comando al nodo situado en <ip> (predeterminado: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format Actualizar billetera al formato actual - + Set key pool size to <n> (default: 100) Ajusta el numero de claves en reserva <n> (predeterminado: 100) - + Rescan the block chain for missing wallet transactions Rescanea la cadena de bloques para transacciones perdidas de la cartera - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opciones SSL: (ver la Bitcoin Wiki para instrucciones de configuración SSL) - - - - + Use OpenSSL (https) for JSON-RPC connections Usa OpenSSL (https) para las conexiones JSON-RPC - + Server certificate file (default: server.cert) Certificado del servidor (Predeterminado: server.cert) - + Server private key (default: server.pem) Clave privada del servidor (Predeterminado: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrados aceptados (Predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Este mensaje de ayuda - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - No se puede obtener permiso de trabajo en la carpeta de datos %s. Probablemente Bitcoin ya se está ejecutando. + + Unable to bind to %s on this computer (bind returned error %d, %s) + No es posible escuchar en el %s en este ordenador (bind returned error %d, %s) + + + + Connect through socks proxy + Conecta mediante proxy socks + + + + Allow DNS lookups for -addnode, -seednode and -connect + Permite búsqueda DNS para addnode y connect - - Bitcoin - Bitcoin - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Cargando direcciónes... - - Error loading blkindex.dat - Error cargando blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Error cargando wallet.dat: Billetera corrupta - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Error cargando wallet.dat: Billetera necesita una vercion reciente de Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Error cargando wallet.dat: Billetera necesita una vercion reciente de CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - La billetera necesita ser reescrita: reinicie Bitcoin para completar + + Wallet needed to be rewritten: restart CasinoCoin to complete + La billetera necesita ser reescrita: reinicie CasinoCoin para completar - + Error loading wallet.dat Error cargando wallet.dat - + Invalid -proxy address: '%s' - + Dirección -proxy invalida: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Cannot resolve -bind address: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Cantidad inválida para -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Error: Billetera bloqueada, no es posible crear la transacción - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Error: Esta transación requiere una comisión de al menos %s por su cantidad, complejidad o uso de fondos recibidos recientemente. - - - - Error: Transaction creation failed - Error: La transacción no se pudo crear - - - - Sending... - Enviando... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Error: La transacción fue rechazada. Esto puede haber ocurrido si alguna de las monedas ya estaba gastada o si ha usado una copia de wallet.dat y las monedas se gastaron en la copia pero no se han marcado como gastadas aqui. - - - + Invalid amount Cantidad inválida - + Insufficient funds Fondos insuficientes - + Loading block index... Cargando el index de bloques... - + Add a node to connect to and attempt to keep the connection open - + Agrega un nodo para conectarse and attempt to keep the connection open - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + No es posible escuchar en el %s en este ordenador. Probablemente CasinoCoin ya se está ejecutando. - - Find peers using internet relay chat (default: 0) - Buscar pares usando 'internet relay chat (IRC)' (predeterminado: 0) - - - - Accept connections from outside (default: 1) - Aceptar conexiones desde el exterior (predeterminado: 1) - - - - Find peers using DNS lookup (default: 1) - Buscar pares usando el sistema DNS (predeterminado: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - + Fee per KB to add to transactions you send - + Comisión por kB para adicionarla a las transacciones enviadas - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Cargando cartera... - + Cannot downgrade wallet - - Cannot initialize keypool - - - - + Cannot write default address - + Rescanning... Rescaneando... - + Done loading Carga completa - + To use the %s option - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - - - - + Error Error - - An error occured while setting up the RPC port %i for listening: %s - Ha ocurrido un error estableciendo el puerto RPC %i en modo escucha: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Precaución: Por favor revise que la fecha y hora de tu ordenador son correctas. Si tu reloj está mal configurado Bitcoin no funcionará correctamente. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index aafd7a2..9c9b2a1 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -3,134 +3,178 @@ AboutDialog - - About Bitcoin - + + About CasinoCoin + CasinoCoinist - - <b>Bitcoin</b> version - + + <b>CasinoCoin</b> version + <b>CasinoCoini</b> versioon - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + ⏎ +See on eksperimentaalne tarkvara.⏎ +⏎ +Levitatud MIT/X11 tarkvara litsentsi all, vaata kaasasolevat faili COPYING või http://www.opensource.org/licenses/mit-license.php⏎ +⏎ +Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenSSL Toolkitis (http://www.openssl.org/) ja Eric Young'i poolt loodud krüptograafilist tarkvara (eay@cryptsoft.com) ning Thomas Bernard'i loodud UPnP tarkvara. + + + + Copyright + Autoriõigus + + + + The CasinoCoin developers AddressBookPage - + Address Book - + Aadressiraamat - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - - - - + Double-click to edit address or label - + Topeltklõps aadressi või märgise muutmiseks - + Create a new address Loo uus aadress - + Copy the currently selected address to the system clipboard - + Kopeeri märgistatud aadress vahemällu - + &New Address - + &Uus aadress - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Maksete saamiseks kasutatavad CasinoCoini aadressid. Maksjate paremaks jälgimiseks võib igaühele anda erineva. + + + &Copy Address - + &Aadressi kopeerimine - + Show &QR Code + Kuva %QR kood + + + + Sign a message to prove you own a CasinoCoin address + Allkirjasta sõnum, et tõestada Bitconi aadressi olemasolu. + + + + Sign &Message + Allkirjasta &Sõnum + + + + Delete the currently selected address from the list + Kustuta märgistatud aadress loetelust + + + + Export the data in the current tab to a file - - Sign a message to prove you own this address + + &Export - - &Sign Message - + + Verify a message to ensure it was signed with a specified CasinoCoin address + Kinnita sõnum tõestamaks selle allkirjastatust määratud CasinoCoini aadressiga. - - Delete the currently selected address from the list. Only sending addresses can be deleted. - + + &Verify Message + &Kinnita Sõnum - + &Delete &Kustuta - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Need on sinu CasinoCoini aadressid maksete saatmiseks. Müntide saatmisel kontrolli alati summat ning saaja aadressi. + + + Copy &Label - + &Märgise kopeerimine - + &Edit - + &Muuda - + + Send &Coins + Saada &Münte + + + Export Address Book Data - + Ekspordi Aadressiraamat - + Comma separated file (*.csv) - + Komaeraldatud fail (*.csv) - + Error exporting Viga eksportimisel - + Could not write to file %1. - + Tõrge faili kirjutamisel %1. AddressTableModel - + Label Silt - + Address Aadress - + (no label) (silti pole) @@ -138,2362 +182,2756 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Salafraasi dialoog - + Enter passphrase - + Sisesta salafraas - + New passphrase - + Uus salafraas - + Repeat new passphrase - + Korda salafraasi - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - + Sisesta rahakotile uus salafraas.<br/>Palun kasuta salafraasina <b>vähemalt 10 tähte/numbrit/sümbolit</b>, või <b>vähemalt 8 sõna</b>. - + Encrypt wallet - + Krüpteeri rahakott - + This operation needs your wallet passphrase to unlock the wallet. - + See toiming nõuab sinu rahakoti salafraasi. - + Unlock wallet - + Tee rahakott lukust lahti. - + This operation needs your wallet passphrase to decrypt the wallet. - + See toiming nõuab sinu rahakoti salafraasi. - + Decrypt wallet - + Dekrüpteeri rahakott. - + Change passphrase - + Muuda salafraasi - + Enter the old and new passphrase to the wallet. - + Sisesta rahakoti vana ning uus salafraas. - + Confirm wallet encryption - + Kinnita rahakoti krüpteering - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Hoiatus: Kui sa kaotad oma, rahakoti krüpteerimisel kasutatud, salafraasi, siis <b>KAOTAD KA KÕIK OMA CASINOCOINID</b>! - - + + Are you sure you wish to encrypt your wallet? + Kas soovid oma rahakoti krüpteerida? + + + + 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. + TÄHTIS: Kõik varasemad rahakoti varundfailid tuleks üle kirjutada äsja loodud krüpteeritud rahakoti failiga. Turvakaalutlustel tühistatakse krüpteerimata rahakoti failid alates uue, krüpteeritud rahakoti, kasutusele võtust. + + + + + Warning: The Caps Lock key is on! + Hoiatus: Caps Lock on sisse lülitatud! + + + + Wallet encrypted - + Rahakott krüpteeritud - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin sulgub krüpteeringu lõpetamiseks. Pea meeles, et rahakoti krüpteerimine ei välista casinocoinide vargust, kui sinu arvuti on nakatunud pahavaraga. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed - + Tõrge rahakoti krüpteerimisel - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + Rahakoti krüpteering ebaõnnestus tõrke tõttu. Sinu rahakotti ei krüpteeritud. - - + + The supplied passphrases do not match. - + Salafraasid ei kattu. - + Wallet unlock failed - + Rahakoti avamine ebaõnnestus - - - + + + The passphrase entered for the wallet decryption was incorrect. - + Rahakoti salafraas ei ole õige. - + Wallet decryption failed - + Rahakoti dekrüpteerimine ei õnnestunud - - Wallet passphrase was succesfully changed. - + + Wallet passphrase was successfully changed. + Rahakoti salafraasi muutmine õnnestus. BitcoinGUI - - Bitcoin Wallet - - - - + Sign &message... - + Signeeri &sõnum - - Show/Hide &Bitcoin - - - - + Synchronizing with network... - + Võrgusünkimine... - + &Overview &Ülevaade - + Show general overview of wallet - + Kuva rahakoti üld-ülevaade - + &Transactions &Tehingud - + Browse transaction history Sirvi tehingute ajalugu - - &Address Book - &Aadressiraamat - - - + Edit the list of stored addresses and labels - + Salvestatud aadresside ja märgiste loetelu muutmine - - &Receive coins - - - - + Show the list of addresses for receiving payments - + Kuva saadud maksete aadresside loetelu - - &Send coins - - - - - Prove you control an address - - - - + E&xit - + V&älju - + Quit application - + Väljumine - - &About %1 - + + Show information about CasinoCoin + Kuva info CasinoCoini kohta - - Show information about Bitcoin - - - - + About &Qt - + Teave &Qt kohta - + Show information about Qt - + Kuva Qt kohta käiv info - + &Options... &Valikud... - + &Encrypt Wallet... - + &Krüpteeri Rahakott - + &Backup Wallet... - + &Varunda Rahakott - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Salafraasi muutmine - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Impordi blokid kettalt... - - &Export... - &Ekspordi... + + Reindexing blocks on disk... + Kettal olevate blokkide re-indekseerimine... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Saada münte CasinoCoini aadressile - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Muuda CasinoCoini seadeid - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - - - - + Backup wallet to another location - + Varunda rahakott teise asukohta - + Change the passphrase used for wallet encryption - + Rahakoti krüpteerimise salafraasi muutmine - + &Debug window - + &Debugimise aken - + Open debugging and diagnostic console - + Ava debugimise ja diagnostika konsool - + &Verify message... - + &Kontrolli sõnumit... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Rahakott + + + + &Send + &Saada + + + + &Receive + &Saama + + + + &Addresses + &Aadressid + + + + &About CasinoCoin + %CasinoCoinist + + + + &Show / Hide + &Näita / Peida + + + + Show or hide the main Window + Näita või peida peaaken + + + + Encrypt the private keys that belong to your wallet + Krüpteeri oma rahakoti privaatvõtmed + + + + Sign messages with your CasinoCoin addresses to prove you own them + Omandi tõestamiseks allkirjasta sõnumid oma CasinoCoini aadressiga + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Kinnita sõnumid kindlustamaks et need allkirjastati määratud CasinoCoini aadressiga + + + &File &Fail - + &Settings &Seaded - + &Help - &Abiinfo + &Abi - + Tabs toolbar - + Vahelehe tööriistariba - - Actions toolbar - - - - - + + [testnet] + [testnet] + + + + CasinoCoin client + CasinoCoini klient + + + + %n active connection(s) to CasinoCoin network + %n aktiivne ühendus CasinoCoini võrku%n aktiivset ühendust CasinoCoini võrku + + + + No block source available... - - - Bitcoin client - - - - - %n active connection(s) to Bitcoin network - + + Processed %1 of %2 (estimated) blocks of transaction history. + Protsessitud %1 (arvutuslikult) tehingu ajaloo blokki %2-st. - - Downloaded %1 blocks of transaction history. - + + Processed %1 blocks of transaction history. + Protsessitud %1 tehingute ajaloo blokki. - - %n second(s) ago - + + %n hour(s) + %n tund%n tundi - - %n minute(s) ago - + + %n day(s) + %n päev%n päeva - - %n hour(s) ago - - - - - %n day(s) ago - + + %n week(s) + %n nädal%n nädalat - + + %1 behind + %1 maas + + + + Last received block was generated %1 ago. + Viimane saabunud blokk loodi %1 tagasi. + + + + Transactions after this will not yet be visible. + Peale seda ei ole tehingud veel nähtavad. + + + + Error + Tõrge + + + + Warning + Hoiatus + + + + Information + Informatsioon + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + See tehing ületab mahupiirangu. Saatmine on võimalik %1, node'idele ning võrgustiku toetuseks, makstava lisatasu eest. Kas nõustud lisatasuga? + + + Up to date - + Ajakohane - + Catching up... - + Jõuan... - - Last received block was generated %1. - - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - - - - + Confirm transaction fee - + Kinnita tehingu tasu - + Sent transaction - + Saadetud tehing - + Incoming transaction - + Sisenev tehing - + Date: %1 Amount: %2 Type: %3 Address: %4 - + Kuupäev: %1⏎ +Summa: %2⏎ +Tüüp: %3⏎ +Aadress: %4⏎ - + + + URI handling + URI käsitsemine + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI ei suudeta parsida. Põhjuseks võib olla kehtetu CasinoCoini aadress või vigased URI parameetrid. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - + Rahakott on <b>krüpteeritud</b> ning hetkel <b>avatud</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> - + Rahakott on <b>krüpteeritud</b> ning hetkel <b>suletud</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ilmnes kriitiline tõrge. CasinoCoin suletakse turvakaalutluste tõttu. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Võrgu Häire EditAddressDialog - + Edit Address Muuda aadressi - + &Label - Si&lt + &Märgis - + The label associated with this address book entry - + Selle aadressiraamatu kirjega seotud märgis - + &Address - + &Aadress - + The address associated with this address book entry. This can only be modified for sending addresses. - + Selle aadressiraamatu kirjega seotud aadress. Võimalik muuta ainult aadresside saatmiseks. - + New receiving address - + Uus sissetulev aadress - + New sending address - + Uus väljaminev aadress - + Edit receiving address - + Sissetulevate aadresside muutmine - + Edit sending address - + Väljaminevate aadresside muutmine - + The entered address "%1" is already in the address book. - + Selline aadress on juba olemas: "%1" - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Sisestatud aadress "%1" ei ole CasinoCoinis kehtiv. - + Could not unlock wallet. - + Rahakotti ei avatud - + New key generation failed. - + Tõrge uue võtme loomisel. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoini-Qt - + version - + versioon - + Usage: - + Kasutus: - - options - + + command-line options + käsurea valikud - + UI options - + UI valikud - + Set language, for example "de_DE" (default: system locale) - + Keele valik, nt "ee_ET" (vaikeväärtus: system locale) - + Start minimized - + Käivitu tegumiribale - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - - - - - Main - - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - - &Connect through SOCKS4 proxy: - - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - - - - - Port of the proxy (e.g. 1234) - + Käivitamisel teabeakna kuvamine (vaikeväärtus: 1) OptionsDialog - + Options + Valikud + + + + &Main + %Peamine + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + Pay transaction &fee + Tasu tehingu &fee + + + + Automatically start CasinoCoin after logging in to the system. + Käivita CasinoCoin süsteemi logimisel. + + + + &Start CasinoCoin on system login + &Start CasinoCoin sisselogimisel + + + + Reset all client options to default. + Taasta kõik klientprogrammi seadete vaikeväärtused. + + + + &Reset Options + &Lähtesta valikud + + + + &Network + &Võrk + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + CasinoCoini kliendi pordi automaatne avamine ruuteris. Toimib, kui sinu ruuter aktsepteerib UPnP ühendust. + + + + Map port using &UPnP + Suuna port &UPnP kaudu + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Kasuta CasinoCoini võrgustikku ühendumiseks SOCKS turva proxy't (nt Tor'i kasutamisel). + + + + &Connect through SOCKS proxy: + %Connect läbi turva proxi: + + + + Proxy &IP: + Proxi &IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + Proxi IP (nt 127.0.0.1) + + + + &Port: + &Port: + + + + Port of the proxy (e.g. 9050) + Proxi port (nt 9050) + + + + SOCKS &Version: + Turva proxi SOCKS &Version: + + + + SOCKS version of the proxy (e.g. 5) + Turva proxi SOCKS versioon (nt 5) + + + + &Window + &Aken + + + + Show only a tray icon after minimizing the window. + Minimeeri systray alale. + + + + &Minimize to the tray instead of the taskbar + &Minimeeri systray alale + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Sulgemise asemel minimeeri aken. Selle valiku tegemisel suletakse programm Menüüst "Välju" käsuga. + + + + M&inimize on close + M&inimeeri sulgemisel + + + + &Display + &Kuva + + + + User Interface &language: + Kasutajaliidese &keel: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Kasutajaliidese keele valimise koht. Valik rakendub CasinoCoini käivitamisel. + + + + &Unit to show amounts in: + Summade kuvamise &Unit: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Vali liideses ning müntide saatmisel kuvatav vaikimisi alajaotus. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Kuvada CasinoCoini aadress tehingute loetelus või mitte. + + + + &Display addresses in transaction list + Tehingute loetelu &Display aadress + + + + &OK + &OK + + + + &Cancel + &Katkesta + + + + &Apply + &Rakenda + + + + default + vaikeväärtus + + + + Confirm options reset + Kinnita valikute algseadistamine + + + + Some settings may require a client restart to take effect. + Mõned seadete muudatused rakenduvad programmi käivitumisel. + + + + Do you want to proceed? + Kas soovid jätkata? + + + + + Warning + Hoiatus + + + + + This setting will take effect after restarting CasinoCoin. + Tehtud valik rakendub CasinoCoini käivitamisel. + + + + The supplied proxy address is invalid. + Sisestatud kehtetu proxy aadress. + OverviewPage - + Form - + Vorm - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Kuvatav info ei pruugi olla ajakohane. Ühenduse loomisel süngitakse sinu rahakott automaatselt Bitconi võrgustikuga, kuid see toiming on hetkel lõpetamata. - + Balance: - + Jääk: - - Number of transactions: - - - - + Unconfirmed: - + Kinnitamata: - + Wallet - + Rahakott - + + Immature: + Ebaküps: + + + + Mined balance that has not yet matured + Mitte aegunud mine'itud jääk + + + <b>Recent transactions</b> - + <b>Uuesti saadetud tehingud</b> - + Your current balance - + Sinu jääk hetkel - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - + Kinnitamata tehingud kokku. Ei kajastu hetke jäägis - - Total number of transactions in wallet - - - - - + + out of sync - + sünkimata + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + CasinoCoin ei käivitu: vajuta-maksa toiming QRCodeDialog - + QR Code Dialog - + QR koodi dialoog - - QR Code - - - - + Request Payment - + Makse taotlus - + Amount: - + Summa: - - BTC - - - - + Label: - + Märgis: - + Message: Sõnum: - + &Save As... - + &Salvesta nimega... - + Error encoding URI into QR Code. - + Tõrge URI'st QR koodi loomisel - + + The entered amount is invalid, please check. + Sisestatud summa on vale, palun kontrolli. + + + Resulting URI too long, try to reduce the text for label / message. - + Tulemuseks on liiga pikk URL, püüa lühendada märgise/teate teksti. - + Save QR Code - + Salvesta QR kood - + PNG Images (*.png) - + PNG pildifail (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Kliendi nimi - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + Kliendi versioon - + &Information - + &Informatsioon - - Client - + + Using OpenSSL version + Kasutan OpenSSL versiooni - + Startup time - + Käivitamise hetk - + Network - + Võrgustik - + Number of connections - + Ühenduste arv - + On testnet - + Testnetis - + Block chain - + Ploki jada - + Current number of blocks - + Plokkide hetkearv - + Estimated total blocks - + Ligikaudne plokkide kogus - + Last block time - + Viimane ploki aeg - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Ava - + + Command-line options + Käsurea valikud + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Näita kehtivate käsurea valikute kuvamiseks CasinoCoini-Qt abiteksti + + + + &Show + &Kuva + + + &Console - + &Konsool - + Build date - + Valmistusaeg - + + CasinoCoin - Debug window + CasinoCoin - debugimise aken + + + + CasinoCoin Core + CasinoCoini tuumik + + + + Debug log file + Debugimise logifail + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Ava CasinoCoini logifail praegusest andmekaustast. Toiminguks võib kuluda kuni mõni sekund. + + + Clear console - + Puhasta konsool - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Teretulemast CasinoCoini RPC konsooli. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Ajaloo sirvimiseks kasuta üles ja alla nooli, ekraani puhastamiseks <b>Ctrl-L</b>. - + Type <b>help</b> for an overview of available commands. - + Ülevaateks võimalikest käsklustest trüki <b>help</b>. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - + Müntide saatmine - + Send to multiple recipients at once - + Saatmine mitmele korraga - - &Add Recipient - + + Add &Recipient + Lisa &Saaja - + Remove all transaction fields - + Eemalda kõik tehingu väljad - + Clear &All - + Puhasta &Kõik - + Balance: - + Jääk: - + 123.456 BTC - + 123,456 BTC - + Confirm the send action - + Saatmise kinnitamine - - &Send - + + S&end + S&aada - + <b>%1</b> to %2 (%3) - + <b>%1</b> kuni %2 (%3) - + Confirm send coins - + Müntide saatmise kinnitamine - + Are you sure you want to send %1? - + Soovid kindlasti saata %1? - + and - + ja - - The recepient address is not valid, please recheck. - + + The recipient address is not valid, please recheck. + Saaja aadress ei ole kehtiv, palun kontrolli. - + The amount to pay must be larger than 0. - + Makstav summa peab olema suurem kui 0. - + The amount exceeds your balance. - + Summa ületab jäägi. - + The total exceeds your balance when the %1 transaction fee is included. - + Summa koos tehingu tasuga %1 ületab sinu jääki. - + Duplicate address found, can only send to each address once per send operation. - + Ühe saatmisega topelt-adressaati olla ei tohi. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Tõrge: Tehingu loomine ebaõnnestus! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Viga: Tehingust keelduti. Nt rahakoti koopia kasutamisel võivad selle põhjustada juba kulutatud mündid. SendCoinsEntry - + Form - + Vorm - + A&mount: - + S&umma: - + Pay &To: - + Maksa &: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Tehingu saaja aadress (nt: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book - + Aadressiraamatusse sisestamiseks märgista aadress - + &Label: - + &Märgis - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - + Choose address from address book - + Vali saaja aadressiraamatust - + Alt+A - + Alt+A - + Paste address from clipboard - + Kleebi aadress vahemälust - + Alt+P - + Alt+P - + Remove this recipient + Saaja eemaldamine + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Sisesta CasinoCoini aadress (nt: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signatuurid - Allkirjasta / Kinnita Sõnum + + + + &Sign Message + &Allkirjastamise teade + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Omandiõigsuse tõestamiseks saad sõnumeid allkirjastada oma aadressiga. Ettevaatust petturitega, kes üritavad saada sinu allkirja endale saada. Allkirjasta ainult korralikult täidetud avaldusi, millega nõustud. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Sõnumi signeerimise aadress (nt: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Vali aadress aadressiraamatust + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Kleebi aadress vahemälust + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Sisesta siia allkirjastamise sõnum + + + + Signature + Signatuur + + + + Copy the current signature to the system clipboard + Kopeeri praegune signatuur vahemällu + + + + Sign the message to prove you own this CasinoCoin address + Allkirjasta sõnum CasinoCoini aadressi sulle kuulumise tõestamiseks + + + + Sign &Message + Allkirjasta &Sõnum + + + + Reset all sign message fields + Tühjenda kõik sõnumi allkirjastamise väljad + + + + + Clear &All + Puhasta &Kõik + + + + &Verify Message + &Kinnita Sõnum + + + + Enter the signing 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. + Kinnitamiseks sisesta allkirjastamise aadress, sõnum (kindlasti kopeeri täpselt ka reavahetused, tühikud, tabulaatorid jms) ning allolev signatuur. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Aadress, millega sõnum allkirjastati (nt: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Kinnita sõnum tõestamaks selle allkirjastatust määratud CasinoCoini aadressiga. + + + + Verify &Message + Kinnita &Sõnum + + + + Reset all verify message fields + Tühjenda kõik sõnumi kinnitamise väljad + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Sisesta CasinoCoini aadress (nt: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Signatuuri genereerimiseks vajuta "Allkirjasta Sõnum" + + + + Enter CasinoCoin signature + Sisesta CasinoCoini allkiri + + + + + The entered address is invalid. + Sisestatud aadress ei kehti. + + + + + + + Please check the address and try again. + Palun kontrolli aadressi ning proovi uuesti. + + + + + The entered address does not refer to a key. + Sisestatud aadress ei viita võtmele. + + + + Wallet unlock was cancelled. + Rahakoti avamine katkestati. + + + + Private key for the entered address is not available. + Sisestatud aadressi privaatvõti ei ole saadaval. + + + + Message signing failed. + Sõnumi signeerimine ebaõnnestus. + + + + Message signed. + Sõnum signeeritud. + + + + The signature could not be decoded. + Signatuuri ei õnnestunud dekodeerida. + + + + + Please check the signature and try again. + Palun kontrolli signatuuri ning proovi uuesti. + + + + The signature did not match the message digest. + Signatuur ei kattunud sõnumi kokkuvõttega. + + + + Message verification failed. + Sõnumi kontroll ebaõnnestus. + + + + Message verified. + Sõnum kontrollitud. + + + + SplashScreen + + + The CasinoCoin developers - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + [testnet] TransactionDesc - - Open for %1 blocks - - - - + Open until %1 - + Avatud kuni %1 - - %1/offline? - + + %1/offline + %/1offline'is - + %1/unconfirmed - + %1/kinnitamata - + %1 confirmations - + %1 kinnitust - - <b>Status:</b> - + + Status + Staatus + + + + , broadcast through %n node(s) + , levita läbi %n node'i, levita läbi %n node'i - + + Date + Kuupäev + + + + Source + Allikas + + + + Generated + Genereeritud + + + + + From + Saatja + + + + + + To + Saaja + + + + + own address + oma aadress + + + + label + märgis + + + + + + + + Credit + Krediit + + + + matures in %n more block(s) + aegub %n bloki pärastaegub %n bloki pärast + + + + not accepted + mitte aktsepteeritud + + + + + + + Debit + Deebet + + + + Transaction fee + Tehingu tasu + + + + Net amount + Neto summa + + + + Message + Sõnum + + + + Comment + Kommentaar + + + + Transaction ID + Tehingu ID + + + + Generated coins must mature 120 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. + Enne, kui loodud münte saab kulutama asuda, peavad need läbima 120 blokki. Kui sina selle bloki lõid, levitati see, bloki jadasse ühendamiseks, võrgustikku. Kui jadasse ühendamine ei õnnestu, muudetakse tema staatus "keeldutud" olekusse ning seda ei saa kulutada. Selline olukord võib juhtuda, kui mõni teine node loob bloki sinuga samal ajal. + + + + Debug information + Debug'imise info + + + + Transaction + Tehing + + + + Inputs + Sisendid + + + + Amount + Kogus + + + + true + õige + + + + false + vale + + + , has not been successfully broadcast yet - + , veel esitlemata + + + + Open for %n more block(s) + Avaneb %n bloki pärastAvaneb %n bloki pärast - - , broadcast through %1 node - - - - - , broadcast through %1 nodes - - - - - <b>Date:</b> - - - - - <b>Source:</b> Generated<br> - - - - - - <b>From:</b> - - - - + unknown tundmatu - - - - - <b>To:</b> - - - - - (yours, label: - - - - - (yours) - - - - - - - - <b>Credit:</b> - - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - - - - - - - <b>Debit:</b> - - - - - <b>Transaction fee:</b> - - - - - <b>Net amount:</b> - - - - - Message: - Sõnum: - - - - Comment: - Kommentaar: - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - - TransactionDescDialog - + Transaction details - + Tehingu üksikasjad - + This pane shows a detailed description of the transaction - + Paan kuvab tehingu detailid TransactionTableModel - + Date Kuupäev - + Type Tüüp - + Address Aadress - + Amount Kogus - - Open for %n block(s) - + + Open for %n more block(s) + Avaneb %n bloki pärastAvaneb %n bloki pärast - + Open until %1 - + Avatud kuni %1 - + Offline (%1 confirmations) - + Ühenduseta (%1 kinnitust) - + Unconfirmed (%1 of %2 confirmations) - + Kinnitamata (%1/%2 kinnitust) - + Confirmed (%1 confirmations) - + Kinnitatud (%1 kinnitust) - - Mined balance will be available in %n more blocks - + + Mined balance will be available when it matures in %n more block(s) + Mine'itud jääk muutub kättesaadavaks %n bloki läbimiselMine'itud jääk muutub kättesaadavaks %n bloki läbimisel - + This block was not received by any other nodes and will probably not be accepted! - + Antud klotsi pole saanud ükski osapool ning tõenäoliselt seda ei aktsepteerita! - + Generated but not accepted - + Loodud, kuid aktsepteerimata - + Received with - + Saadud koos - + Received from - + Kellelt saadud - + Sent to - + Saadetud - + Payment to yourself - + Makse iseendale - + Mined - + Mine'itud - + (n/a) - + (n/a) - + Transaction status. Hover over this field to show number of confirmations. - + Tehingu staatus. Kinnituste arvu kuvamiseks liigu hiire noolega selle peale. - + Date and time that the transaction was received. - + Tehingu saamise kuupäev ning kellaaeg. - + Type of transaction. - + Tehingu tüüp. - + Destination address of transaction. - + Tehingu saaja aadress. - + Amount removed from or added to balance. - + Jäägile lisatud või eemaldatud summa. TransactionView - - + + All - + Kõik - + Today - + Täna - + This week - + Jooksev nädal - + This month - + Jooksev kuu - + Last month - + Eelmine kuu - + This year - + Jooksev aasta - + Range... - + Ulatus... - + Received with - + Saadud koos - + Sent to - + Saadetud - + To yourself - + Iseendale - + Mined - + Mine'itud - + Other - + Muu - + Enter address or label to search - + Otsimiseks sisesta märgis või aadress - + Min amount - + Vähim summa - + Copy address - + Aadressi kopeerimine - + Copy label - + Märgise kopeerimine - + Copy amount - + Kopeeri summa - + + Copy transaction ID + Kopeeri tehingu ID + + + Edit label - + Märgise muutmine - + Show transaction details - + Kuva tehingu detailid - + Export Transaction Data - + Tehinguandmete eksport - + Comma separated file (*.csv) - + Komaeraldatud fail (*.csv) - + Confirmed - + Kinnitatud - + Date Kuupäev - + Type Tüüp - + Label Silt - + Address Aadress - + Amount Kogus - + ID - + ID - + Error exporting Viga eksportimisel - + Could not write to file %1. - + Tõrge faili kirjutamisel %1. - + Range: - + Ulatus: - + to - - - - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - + saaja WalletModel - - Sending... + + Send Coins - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file - - Show only a tray icon after minimizing the window - + + Backup Wallet + Varundatud Rahakott - - M&inimize on close - + + Wallet Data (*.dat) + Rahakoti andmed (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - + + Backup Failed + Varundamine nurjus + + + + There was an error trying to save the wallet data to the new location. + Rahakoti andmete uude kohta salvestamine nurjus. + + + + Backup Successful + Varundamine õnnestus + + + + The wallet data was successfully saved to the new location. + Rahakoti andmete uude kohta salvestamine õnnestus. bitcoin-core - - Bitcoin version - + + CasinoCoin version + CasinoCoini versioon - + Usage: - + Kasutus: - - Send command to -server or bitcoind - + + Send command to -server or casinocoind + Saada käsklus -serverile või casinocoindile - + List commands - + Käskluste loetelu - + Get help for a command - + Käskluste abiinfo - + Options: - + Valikud: - - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Täpsusta sätete fail (vaikimisi: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + Täpsusta PID fail (vaikimisi: casinocoin.pid) - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Täpsusta andmekataloog - + Set database cache size in megabytes (default: 25) - + Sea andmebaasi vahemälu suurus MB (vaikeväärtus: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Kuula ühendusi pordil <port> (vaikeväärtus: 47950 või testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + Säilita vähemalt <n> ühendust peeridega (vaikeväärtus: 125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Peeri aadressi saamiseks ühendu korraks node'iga - + Specify your own public address - + Täpsusta enda avalik aadress - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Ulakate peeride valulävi (vaikeväärtus: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + Mitme sekundi pärast ulakad peerid tagasi võivad tulla (vaikeväärtus: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + RPC pordi %u kuulamiseks seadistamisel ilmnes viga IPv4'l: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Kuula JSON-RPC ühendusel seda porti <port> (vaikeväärtus: 47970 või testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Luba käsurea ning JSON-RPC käsklusi - + Run in the background as a daemon and accept commands - + Tööta taustal ning aktsepteeri käsklusi - + Use the test network - + Testvõrgu kasutamine - - Output extra debugging information - + + Accept connections from outside (default: 1 if no -proxy or -connect) + Luba välisühendusi (vaikeväärtus: 1 kui puudub -proxy või -connect) - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - - - - - Sending... - - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + %s, sul tuleb rpcpassword määrata seadete failis: +%s +Soovitatav on kasutada järgmist juhuslikku parooli: +rpcuser=casinocoinrpc +rpcpassword=%s +(seda parooli ei pea meeles pidama) +Kasutajanimi ning parool EI TOHI kattuda. +Kui faili ei leita, loo see ainult-omaniku-loetavas failiõigustes . +Soovitatav on seadistada tõrgete puhul teavitus; +nt: alertnotify=echo %%s | email -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + RPC pordi %u kuulamiseks seadistamisel ilmnes viga IPv6'l, lülitumine tagasi IPv4'le : %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Määratud aadressiga sidumine ning sellelt kuulamine. IPv6 jaoks kasuta vormingut [host]:port + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Ei suuda määrata ainuõigust andmekaustale %s. Tõenäolisel on CasinoCoin juba avatud. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Tõrge: Tehingust keelduti! Põhjuseks võib olla juba kulutatud mündid, nt kui wallet.dat fail koopias kulutatid mündid, kuid ei märgitud neid siin vastavalt. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Tõrge: Selle tehingu jaoks on nõutav lisatasu vähemalt %s. Põhjuseks võib olla summa suurus, keerukus või hiljuti saadud summade kasutamine! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Käivita käsklus, kui saabub tähtis hoiatus (%s cmd's asendatakse sõnumiga) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Käivita käsklus, kui rahakoti tehing muutub (%s cmd's muudetakse TxID'ks) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Sea "kõrge tähtsusega"/"madala tehingu lisatasuga" tehingute maksimumsuurus baitides (vaikeväärtus: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + See on test-versioon - kasutamine omal riisikol - ära kasuta mining'uks ega kaupmeeste programmides + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Hoiatus: -paytxfee on seatud väga kõrgeks! See on sinu poolt makstav tehingu lisatasu. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Hoiatus: Kuvatavad tehingud ei pruugi olla korrektsed! Sina või node'id peate tegema uuenduse. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Hoiatus: Palun kontrolli oma arvuti kuupäeva/kellaaega! Kui arvuti kell on vale, siis CasinoCoin ei tööta korralikult + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Hoiatus: ilmnes tõrge wallet.dat faili lugemisel! Võtmed on terved, kuid tehingu andmed või aadressiraamatu kirjed võivad olla kadunud või vigased. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Hoiatus: toimus wallet.dat faili andmete päästmine! Originaal wallet.dat nimetati kaustas %s ümber wallet.{ajatempel}.bak'iks, jäägi või tehingute ebakõlade puhul tuleks teha backup'ist taastamine. + + + + Attempt to recover private keys from a corrupt wallet.dat + Püüa vigasest wallet.dat failist taastada turvavõtmed + + + + Block creation options: + Blokeeri loomise valikud: + + + + Connect only to the specified node(s) + Ühendu ainult määratud node'i(de)ga + + + + Corrupted block database detected + Tuvastati vigane bloki andmebaas + + + + Discover own IP address (default: 1 when listening and no -externalip) + Leia oma IP aadress (vaikeväärtus: 1, kui kuulatakse ning puudub -externalip) + + + + Do you want to rebuild the block database now? + Kas soovid bloki andmebaasi taastada? + + + + Error initializing block database + Tõrge bloki andmebaasi käivitamisel + + + + Error initializing wallet database environment %s! + Tõrge rahakoti keskkonna %s käivitamisel! + + + + Error loading block database + Tõrge bloki baasi lugemisel + + + + Error opening block database + Tõrge bloki andmebaasi avamisel + + + + Error: Disk space is low! + Tõrge: liiga vähe kettaruumi! + + + + Error: Wallet locked, unable to create transaction! + Tõrge: Rahakott on lukus, tehingu loomine ei ole võimalik! + + + + Error: system error: + Tõrge: süsteemi tõrge: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Pordi kuulamine nurjus. Soovikorral kasuta -listen=0. + + + + Failed to read block info + Tõrge bloki sisu lugemisel + + + + Failed to read block + Bloki lugemine ebaõnnestus + + + + Failed to sync block index + Bloki indeksi sünkimine ebaõnnestus + + + + Failed to write block index + Bloki indeksi kirjutamine ebaõnnestus + + + + Failed to write block info + Bloki sisu kirjutamine ebaõnnestus + + + + Failed to write block + Tõrge bloki sisu kirjutamisel + + + + Failed to write file info + Tõrge faili info kirjutamisel + + + + Failed to write to coin database + Tõrge mündi andmebaasi kirjutamisel + + + + Failed to write transaction index + Tehingu indeksi kirjutamine ebaõnnestus + + + + Failed to write undo data + Tagasivõtmise andmete kirjutamine ebaõnnestus + + + + Find peers using DNS lookup (default: 1 unless -connect) + Otsi DNS'i lookup'i kastavaid peere (vaikeväärtus: 1, kui mitte -connect) + + + + Generate coins (default: 0) - + + How many blocks to check at startup (default: 288, 0 = all) + Käivitamisel kontrollitavate blokkide arv (vaikeväärtus: 288, 0=kõik) + + + + How thorough the block verification is (0-4, default: 3) + Blokkide kontrollimise põhjalikkus (0-4, vaikeväärtus: 3) + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + Taasta bloki jada indeks blk000??.dat failist + + + + Set the number of threads to service RPC calls (default: 4) + Määra RPC kõnede haldurite arv (vaikeväärtus: 4) + + + + Verifying blocks... + Kontrollin blokke... + + + + Verifying wallet... + Kontrollin rahakotti... + + + + Imports blocks from external blk000??.dat file + Impordi blokid välisest blk000??.dat failist + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Informatsioon + + + + Invalid -tor address: '%s' + Vigane -tor aadress: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + Säilita kogu tehingu indeks (vaikeväärtus: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maksimaalne saamise puhver -connection kohta , <n>*1000 baiti (vaikeväärtus: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maksimaalne saatmise puhver -connection kohta , <n>*1000 baiti (vaikeväärtus: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Tunnusta ainult sisseehitatud turvapunktidele vastavaid bloki jadu (vaikeväärtus: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Ühenda ainult node'idega <net> võrgus (IPv4, IPv6 või Tor) + + + + Output extra debugging information. Implies all other -debug* options + Väljund lisa debug'imise infoks. Tuleneb kõikidest teistest -debug* valikutest + + + + Output extra network debugging information + Lisa võrgu debug'imise info väljund + + + + Prepend debug output with timestamp + Varusta debugi väljund ajatempliga + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL valikud: (vaata CasinoCoini Wikist või SSL sätete juhendist) + + + + Select the version of socks proxy to use (4-5, default: 5) + Vali turva proxi SOCKS versioon (4-5, vaikeväärtus: 5) + + + + Send trace/debug info to console instead of debug.log file + Saada jälitus/debug, debug.log faili asemel, konsooli + + + + Send trace/debug info to debugger + Saada jälitus/debug info debuggerile + + + + Set maximum block size in bytes (default: 250000) + Sea maksimaalne bloki suurus baitides (vaikeväärtus: 250000) + + + + Set minimum block size in bytes (default: 0) + Sea minimaalne bloki suurus baitides (vaikeväärtus: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Kahanda programmi käivitamisel debug.log faili (vaikeväärtus: 1, kui ei ole -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Sea ühenduse timeout millisekundites (vaikeväärtus: 5000) + + + + System error: + Süsteemi tõrge: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Kasuta kuulatava pordi määramiseks UPnP ühendust (vaikeväärtus: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Kasuta kuulatava pordi määramiseks UPnP ühendust (vaikeväärtus: 1, kui kuulatakse) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Kasuta varjatud teenustele ligipääsuks proxy't (vaikeväärtus: sama, mis -proxy) + + + + Username for JSON-RPC connections + JSON-RPC ühenduste kasutajatunnus + + + + Warning + Hoiatus + + + + Warning: This version is obsolete, upgrade required! + Hoiatus: versioon on aegunud, uuendus on nõutav! + + + + You need to rebuild the databases using -reindex to change -txindex + Andmebaas tuleb taastada kasutades -reindex, et muuta -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat fail on katki, päästmine ebaõnnestus + + + + Password for JSON-RPC connections + JSON-RPC ühenduste salasõna + + + + Allow JSON-RPC connections from specified IP address + JSON-RPC ühenduste lubamine kindla IP pealt + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Saada käsklusi node'ile IP'ga <ip> (vaikeväärtus: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Käivita käsklus, kui parim plokk muutub (käskluse %s asendatakse ploki hash'iga) + + + + Upgrade wallet to latest format + Uuenda rahakott uusimasse vormingusse + + + + Set key pool size to <n> (default: 100) + Sea võtmete hulgaks <n> (vaikeväärtus: 100) + + + + Rescan the block chain for missing wallet transactions + Otsi ploki jadast rahakoti kadunud tehinguid + + + + Use OpenSSL (https) for JSON-RPC connections + Kasuta JSON-RPC ühenduste jaoks OpenSSL'i (https) + + + + Server certificate file (default: server.cert) + Serveri sertifikaadifail (vaikeväärtus: server.cert) + + + + Server private key (default: server.pem) + Serveri privaatvõti (vaikeväärtus: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Lubatud šiffrid (vaikeväärtus: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Käesolev abitekst + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Selle arvutiga ei ole võimalik siduda %s külge (katse nurjus %d, %s tõttu) + + + + Connect through socks proxy + Ühendu läbi turva proxi + + + + Allow DNS lookups for -addnode, -seednode and -connect + -addnode, -seednode ja -connect tohivad kasutada DNS lookup'i + + + + Loading addresses... + Aadresside laadimine... + + + + Error loading wallet.dat: Wallet corrupted + Viga wallet.dat käivitamisel. Vigane rahakkott + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Viga wallet.dat käivitamisel: Rahakott nõuab CasinoCoini uusimat versiooni + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Rahakott tuli ümberkirjutada: toimingu lõpetamiseks taaskäivita CasinoCoin + + + + Error loading wallet.dat + Viga wallet.dat käivitamisel + + + + Invalid -proxy address: '%s' + Vigane -proxi aadress: '%s' + + + + Unknown network specified in -onlynet: '%s' + Kirjeldatud tundmatu võrgustik -onlynet'is: '%s' + + + + Unknown -socks proxy version requested: %i + Küsitud tundmatu -socks proxi versioon: %i + + + + Cannot resolve -bind address: '%s' + Tundmatu -bind aadress: '%s' + + + + Cannot resolve -externalip address: '%s' + Tundmatu -externalip aadress: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + -paytxfee=<amount> jaoks vigane kogus: '%s' + + + + Invalid amount + Kehtetu summa + + + + Insufficient funds + Liiga suur summa + + + + Loading block index... + Klotside indeksi laadimine... + + + + Add a node to connect to and attempt to keep the connection open + Lisa node ning hoia ühendus avatud + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + %s'ga ei ole võimalik sellest arvutist siduda. CasinoCoin juba töötab. + + + + Fee per KB to add to transactions you send + Minu saadetavate tehingute lisatasu KB kohta + + + + Loading wallet... + Rahakoti laadimine... + + + + Cannot downgrade wallet + Rahakoti vanandamine ebaõnnestus + + + + Cannot write default address + Tõrge vaikimisi aadressi kirjutamisel + + + + Rescanning... + Üleskaneerimine... + + + + Done loading + Laetud + + + + To use the %s option + %s valiku kasutamine + + + Error - + Tõrge - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - + rpcpassword=<password> peab sätete failis olema seadistatud:⏎ +%s⏎ +Kui seda faili ei ole, loo see ainult-omanikule-lugemiseks faili õigustes. \ 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 01a156c..8b00a4b 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -3,566 +3,634 @@ AboutDialog - - About Bitcoin + + About CasinoCoin + CasinoCoin-i buruz + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> bertsioa + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - - <b>Bitcoin</b> version - <b>Bitcoin</b> Bertsio + + Copyright + - - Copyright © 2009-2012 Bitcoin Developers - -This is experimental software. - -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. - -This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + The CasinoCoin developers AddressBookPage - + Address Book Helbide-liburua - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - - - - + Double-click to edit address or label - + Klik bikoitza helbidea edo etiketa editatzeko - + Create a new address Sortu helbide berria - + Copy the currently selected address to the system clipboard - + Kopiatu hautatutako helbidea sistemaren arbelera - + &New Address - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + &Copy Address - + Show &QR Code + Erakutsi &QR kodea + + + + Sign a message to prove you own a CasinoCoin address - - Sign a message to prove you own this address + + Sign &Message - - &Sign Message + + Delete the currently selected address from the list - - Delete the currently selected address from the list. Only sending addresses can be deleted. + + Export the data in the current tab to a file - + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete &Ezabatu - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + &Edit - + + Send &Coins + + + + Export Address Book Data - + Esportatu Helbide-liburuaren datuak - + Comma separated file (*.csv) - + Komaz bereizitako artxiboa (*.csv) - + Error exporting - + Errorea esportatzean - + Could not write to file %1. - + Ezin idatzi %1 artxiboan. AddressTableModel - + Label - + Etiketa - + Address Helbidea - + (no label) - + (etiketarik ez) AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase - + Sartu pasahitza - + New passphrase - + Pasahitz berria - + Repeat new passphrase - + Errepikatu pasahitz berria - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - + Sartu zorrorako pasahitz berria.<br/> Mesedez erabili <b>gutxienez ausazko 10 karaktere</b>, edo <b>gutxienez zortzi hitz</b> pasahitza osatzeko. - + Encrypt wallet - + Enkriptatu zorroa - + This operation needs your wallet passphrase to unlock the wallet. - + Eragiketa honek zorroaren pasahitza behar du zorroa desblokeatzeko. - + Unlock wallet - + Desblokeatu zorroa - + This operation needs your wallet passphrase to decrypt the wallet. - + Eragiketa honek zure zorroaren pasahitza behar du, zorroa desenkriptatzeko. - + Decrypt wallet - + Desenkriptatu zorroa - + Change passphrase - + Aldatu pasahitza - + Enter the old and new passphrase to the wallet. - + Sartu zorroaren pasahitz zaharra eta berria. - + Confirm wallet encryption + Berretsi zorroaren enkriptazioa + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? + + Are you sure you wish to encrypt your wallet? - - + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted + Zorroa enkriptatuta + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. - - Bitcoin 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. - - - - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed - + Zorroaren enkriptazioak huts egin du - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + Zorroaren enkriptazioak huts egin du barne-errore baten ondorioz. Zure zorroa ez da enkriptatu. - - + + The supplied passphrases do not match. - + Eman dituzun pasahitzak ez datoz bat. - + Wallet unlock failed - + Zorroaren desblokeoak huts egin du - - - + + + The passphrase entered for the wallet decryption was incorrect. - + Zorroa desenkriptatzeko sartutako pasahitza okerra da. - + Wallet decryption failed - + Zorroaren desenkriptazioak huts egin du - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. BitcoinGUI - - Bitcoin Wallet - - - - + Sign &message... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... - + Sarearekin sinkronizatzen... - + &Overview - + &Gainbegiratu - + Show general overview of wallet - + Ikusi zorroaren begirada orokorra - + &Transactions - + &Transakzioak - + Browse transaction history - + Ikusi transakzioen historia - - &Address Book - - - - + Edit the list of stored addresses and labels - + Editatu gordetako helbide eta etiketen zerrenda - - &Receive coins - - - - + Show the list of addresses for receiving payments - + Erakutsi ordainketak jasotzeko helbideen zerrenda - - &Send coins - - - - - Prove you control an address - - - - + E&xit - + Irten - + Quit application - + Irten aplikaziotik - - &About %1 - + + Show information about CasinoCoin + Erakutsi CasinoCoin-i buruzko informazioa - - Show information about Bitcoin - - - - + About &Qt - + &Qt-ari buruz - + Show information about Qt - + Erakutsi CasinoCoin-i buruzko informazioa - + &Options... - + &Aukerak... - + &Encrypt Wallet... - + &Backup Wallet... - + &Change Passphrase... - - - ~%n block(s) remaining - - - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... + + Reindexing blocks on disk... - - Send coins to a Bitcoin address + + Send coins to a CasinoCoin address - - Modify configuration options for Bitcoin + + Modify configuration options for CasinoCoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - - - - + Backup wallet to another location - + Change the passphrase used for wallet encryption - + Aldatu zorroa enkriptatzeko erabilitako pasahitza - + &Debug window - + Open debugging and diagnostic console - + &Verify message... - - Verify a message signature + + + CasinoCoin - + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File - + &Artxiboa - + &Settings - + &Ezarpenak - + &Help - + &Laguntza - + Tabs toolbar - + Fitxen tresna-barra - - Actions toolbar - - - - - + + [testnet] - + [testnet] - - - Bitcoin client + + CasinoCoin client - - %n active connection(s) to Bitcoin network - + + %n active connection(s) to CasinoCoin network + Konexio aktibo %n CasinoCoin-en sarera%n konexio aktibo CasinoCoin-en sarera - - Downloaded %1 blocks of transaction history. + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. - - %n second(s) ago + + %n hour(s) - - %n minute(s) ago + + %n day(s) - - %n hour(s) ago - - - - - %n day(s) ago + + %n week(s) - + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date - + Egunean - + Catching up... - + Eguneratzen... - - Last received block was generated %1. - - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - - - - + Confirm transaction fee - + Sent transaction - + Bidalitako transakzioa - + Incoming transaction - + Sarrerako transakzioa - + Date: %1 Amount: %2 Type: %3 @@ -571,538 +639,485 @@ Address: %4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - + Zorroa <b>enkriptatuta</b> eta <b>desblokeatuta</b> dago une honetan - + Wallet is <b>encrypted</b> and currently <b>locked</b> - + Zorroa <b>enkriptatuta</b> eta <b>blokeatuta</b> dago une honetan - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address - + Editatu helbidea - + &Label - + &Etiketa - + The label associated with this address book entry - + Helbide-liburuko sarrera honekin lotutako etiketa - + &Address - + &Helbidea - + The address associated with this address book entry. This can only be modified for sending addresses. - + Helbide-liburuko sarrera honekin lotutako helbidea. Bidaltzeko helbideeta soilik alda daiteke. - + New receiving address - + Jasotzeko helbide berria - + New sending address - + Bidaltzeko helbide berria - + Edit receiving address - + Editatu jasotzeko helbidea - + Edit sending address - + Editatu bidaltzeko helbidea - + The entered address "%1" is already in the address book. + Sartu berri den helbidea, "%1", helbide-liburuan dago jadanik. + + + + The entered address "%1" is not a valid CasinoCoin address. - - The entered address "%1" is not a valid Bitcoin address. - - - - + Could not unlock wallet. - + Ezin desblokeatu zorroa. - + New key generation failed. - + Gako berriaren sorrerak huts egin du. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + Usage: - - options + + command-line options - + UI options - + Set language, for example "de_DE" (default: system locale) - + Start minimized - + Show splash screen on startup (default: 1) - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - - - - - Main - - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - - &Connect through SOCKS4 proxy: - - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - - - - - Port of the proxy (e.g. 1234) - - - OptionsDialog - + Options + Aukerak + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. OverviewPage - + Form + Inprimakia + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - - - 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. - - - - + Balance: - + Saldoa: - - Number of transactions: - - - - + Unconfirmed: - + Konfirmatu gabe: - + Wallet - + + Immature: + + + + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> - + <b>Azken transakzioak</b> - + Your current balance - + Zure uneko saldoa - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - + Oraindik konfirmatu gabe daudenez, uneko saldoab kontatu gabe dagoen transakzio kopurua - - Total number of transactions in wallet - - - - - + + out of sync + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + QRCodeDialog - + QR Code Dialog - - QR Code - - - - + Request Payment - + Amount: - + Kopurua - - BTC - - - - + Label: - + &Etiketa: - + Message: - + Mezua - + &Save As... - + Gorde honela... - + Error encoding URI into QR Code. - + + The entered amount is invalid, please check. + + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + PNG Images (*.png) @@ -1110,125 +1125,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Number of connections - + On testnet - + Block chain - + Current number of blocks - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1236,109 +1272,109 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - + Bidali txanponak - + Send to multiple recipients at once + Bidali hainbat jasotzaileri batera + + + + Add &Recipient - - &Add Recipient - - - - + Remove all transaction fields - + Clear &All - + Balance: - + Saldoa: - + 123.456 BTC - + 123.456 BTC - + Confirm the send action + Berretsi bidaltzeko ekintza + + + + S&end - - &Send - - - - + <b>%1</b> to %2 (%3) - + <b>%1</b> honi: %2 (%3) - + Confirm send coins - + Berretsi txanponak bidaltzea - + Are you sure you want to send %1? - + Ziur zaude %1 bidali nahi duzula? - + and + eta + + + + The recipient address is not valid, please recheck. - - The recepient address is not valid, please recheck. - - - - + The amount to pay must be larger than 0. - + Ordaintzeko kopurua 0 baino handiagoa izan behar du. - + The amount exceeds your balance. - + The total exceeds your balance when the %1 transaction fee is included. - + Duplicate address found, can only send to each address once per send operation. - - Error: Transaction creation failed. + + Error: Transaction creation failed! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -1346,1154 +1382,1536 @@ Address: %4 SendCoinsEntry - + Form - + Inprimakia - + A&mount: - + K&opurua: - + Pay &To: + Ordaindu &honi: + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) - - + + Enter a label for this address to add it to your address book - + Sartu etiketa bat helbide honetarako, eta gehitu zure helbide-liburuan - + &Label: - + &Etiketa: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - + Choose address from address book - + Alt+A - + Alt+A - + Paste address from clipboard - + Itsatsi helbidea arbeletik - + Alt+P - + Alt+P - + Remove this recipient + Ezabatu jasotzaile hau + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Sartu Bitocin helbide bat (adb.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Itsatsi helbidea arbeletik + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Sartu Bitocin helbide bat (adb.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] TransactionDesc - - Open for %1 blocks - - - - + Open until %1 + Zabalik %1 arte + + + + %1/offline - - %1/offline? - - - - + %1/unconfirmed - + %1/konfirmatu gabe - + %1 confirmations + %1 konfirmazioak + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + Data + + + + Source - - <b>Status:</b> + + Generated - + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + Kopurua + + + + true + + + + + false + + + + , has not been successfully broadcast yet - + , ez da arrakastaz emititu oraindik + + + + Open for %n more block(s) + - - , broadcast through %1 node - - - - - , broadcast through %1 nodes - - - - - <b>Date:</b> - - - - - <b>Source:</b> Generated<br> - - - - - - <b>From:</b> - - - - + unknown - - - - - - - <b>To:</b> - - - - - (yours, label: - - - - - (yours) - - - - - - - - <b>Credit:</b> - - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - - - - - - - <b>Debit:</b> - - - - - <b>Transaction fee:</b> - - - - - <b>Net amount:</b> - - - - - Message: - - - - - Comment: - - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - + ezezaguna TransactionDescDialog - + Transaction details - + Transakzioaren xehetasunak - + This pane shows a detailed description of the transaction - + Panel honek transakzioaren deskribapen xehea erakusten du TransactionTableModel - + Date - + Data - + Type - + Mota - + Address Helbidea - + Amount - + Kopurua - - Open for %n block(s) + + Open for %n more block(s) - + Open until %1 - + Zabalik %1 arte - + Offline (%1 confirmations) - + Offline (%1 konfirmazio) - + Unconfirmed (%1 of %2 confirmations) - + Confirmed (%1 confirmations) - + Konfirmatuta (%1 konfirmazio) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) - + This block was not received by any other nodes and will probably not be accepted! - + Bloke hau ez du beste inongo nodorik jaso, eta seguruenik ez da onartuko! - + Generated but not accepted - + Sortua, baina ez onartua - + Received with - + Jasoa honekin: - + Received from - + Sent to - + Honi bidalia: - + Payment to yourself - + Ordainketa zeure buruari - + Mined - + Bildua - + (n/a) - + (n/a) - + Transaction status. Hover over this field to show number of confirmations. - + Transakzioaren egoera. Pasatu sagua gainetik konfirmazio kopurua ikusteko. - + Date and time that the transaction was received. - + Transakzioa jasotako data eta ordua. - + Type of transaction. - + Transakzio mota. - + Destination address of transaction. - + Transakzioaren xede-helbidea. - + Amount removed from or added to balance. - + Saldoan kendu edo gehitutako kopurua. TransactionView - - + + All - + Denak - + Today - + Gaur - + This week - + Aste honetan - + This month - + Hil honetan - + Last month - + Azken hilean - + This year - + Aurten - + Range... - + Muga... - + Received with - + Jasota honekin: - + Sent to - + Hona bidalia: - + To yourself - + Zeure buruari - + Mined - + Bildua - + Other - + Beste - + Enter address or label to search - + Sartu bilatzeko helbide edo etiketa - + Min amount - + Kopuru minimoa - + Copy address - + Kopiatu helbidea - + Copy label - + Kopiatu etiketa - + Copy amount - + + Copy transaction ID + + + + Edit label - + Show transaction details - + Export Transaction Data - + Transakzioaren xehetasunak - + Comma separated file (*.csv) - + Komaz bereizitako artxiboa (*.csv) - + Confirmed - + Date - + Data - + Type - + Mota - + Label - + Etiketa - + Address Helbidea - + Amount - + Kopurua - + ID - + Error exporting - + Errorea esportatzean - + Could not write to file %1. - + Ezin idatzi %1 artxiboan. - + Range: - + to - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... + + Send Coins - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file - - Show only a tray icon after minimizing the window + + Backup Wallet - - M&inimize on close + + Wallet Data (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. bitcoin-core - - Bitcoin version - + + CasinoCoin version + Botcoin bertsioa - + Usage: - - Send command to -server or bitcoind + + Send command to -server or casinocoind - + List commands - + Komandoen lista - + Get help for a command - + Laguntza komando batean - + Options: - + Aukerak - - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Ezarpen fitxategia aukeratu (berezkoa: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + pid fitxategia aukeratu (berezkoa: casinocoind.pid) - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Set database cache size in megabytes (default: 25) - - Set database disk log size in megabytes (default: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands - + Use the test network - - Output extra debugging information + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - - - - - Sending... - - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + Laguntza mezu hau + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + Birbilatzen... + + + + Done loading + Zamaketa amaitua + + + + To use the %s option + + + + Error - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index e918c46..6f49f23 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -3,124 +3,155 @@ AboutDialog - - About Bitcoin - در مورد بیتکویین - + + About CasinoCoin + در مورد CasinoCoin - - <b>Bitcoin</b> version - نسخه + + <b>CasinoCoin</b> version + نسخه CasinoCoin - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - کپی رایت © 2012-2009 Bitcoin Developers - -این یک نرم‌افزار آزمایشی است. - -توزیع شده تحت امتیاز نرم‌افزار MIT/X11، از فایل همراه با عنوان license.txt یا http://www.opensource.org/licenses/mit-license.php دیدن کنید. - -این محصول از نرم‌افزار ساخته شده در OpenSSL Project برای استفاده در جعبه ابزار OpenSSL‏ (http://www.openssl.org/‎)، نرم‌افزار نهفته نوشته شده توسط اریک یانگ (eay@cryptsoft.com) و نرم‌افزار UPnP نوشته شده توسط توماس برنارد تشکیل شده است. + ⏎ ⏎ این نسخه نرم افزار آزمایشی است⏎ ⏎ نرم افزار تحت لیسانس MIT/X11 منتشر شده است. به فایل coping یا آدرس http://www.opensource.org/licenses/mit-license.php. مراجعه شود⏎ ⏎ این محصول شامل نرم افزاری است که با OpenSSL برای استفاده از OpenSSL Toolkit (http://www.openssl.org/) و نرم افزار نوشته شده توسط اریک یانگ (eay@cryptsoft.com ) و UPnP توسط توماس برنارد طراحی شده است. + + + + Copyright + + + + + The CasinoCoin developers + AddressBookPage - + Address Book - دفتر آدرس + فهرست آدرس - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - ااینجا آدرسهای بیتکویین هستند برای در یافت پر داختها. شما می توانید از مسیر های متفاوت پر داخت در بیابید بدین دلیل شما می توانید مسیر پر داخت کننده نگهداری کنید -درس روی پنجره اصلی نمایش می شود - - - + Double-click to edit address or label برای ویرایش آدرس یا بر چسب دو بار کلیک کنید - + Create a new address - آدرس نو ایجاد کنید + آدرس جدید ایجاد کنید - + Copy the currently selected address to the system clipboard آدرس انتخاب شده در سیستم تخته رسم گیره دار کپی کنید - + &New Address - + آدرس جدید - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + این آدرسها، آدرسهای casinocoin شما برای دریافت وجوه هستند. شما ممکن است آدرسهای متفاوت را به هر گیرنده اختصاص دهید که بتوانید مواردی که پرداخت می کنید را پیگیری نمایید + + + &Copy Address - + کپی آدرس - + Show &QR Code نمایش &کد QR - - Sign a message to prove you own this address - یک پیام را امضا کنید تا ثابت کنید صاحب این نشانی هستید + + Sign a message to prove you own a CasinoCoin address + پیام را برای اثبات آدرس CasinoCoin خود امضا کنید - - &Sign Message - &امضای پیام + + Sign &Message + امضا و پیام - - Delete the currently selected address from the list. Only sending addresses can be deleted. - آدرس انتخاب شده از لیست حذف کنید. فقط آدرسهای ارسال شده می شود حفذ کرد + + Delete the currently selected address from the list + آدرس انتخاب شده در سیستم تخته رسم گیره دا حذف - + + Export the data in the current tab to a file + داده ها نوارِ جاری را به فایل انتقال دهید + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + یک پیام را برای حصول اطمینان از ورود به سیستم با آدرس casinocoin مشخص، شناسایی کنید + + + + &Verify Message + شناسایی پیام + + + &Delete - آدرس نو + حذف - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + کپی و برچسب گذاری - + &Edit + ویرایش + + + + Send &Coins - + Export Address Book Data آدرس انتخاب شده در سیستم تخته رسم گیره دار کپی کنید - + Comma separated file (*.csv) - Comma فایل جدا + Comma separated file (*.csv) - + Error exporting - خطای صادرت + خطای صدور - + Could not write to file %1. تا فایل %1 نمی شود نوشت @@ -128,450 +159,479 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label - ر چسب + بر چسب - + Address - ایل جدا + آدرس - + (no label) - خطای صادرت + بدون برچسب AskPassphraseDialog - + Passphrase Dialog - + دیالوگ Passphrase - + Enter passphrase وارد عبارت عبور - + New passphrase عبارت عبور نو - + Repeat new passphrase تکرار عبارت عبور نو - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. وارد کنید..&lt;br/&gt عبارت عبور نو در پنجره 10 یا بیشتر کاراکتورهای تصادفی استفاده کنید &lt;b&gt لطفا عبارت عبور - + Encrypt wallet رمز بندی پنجره - + This operation needs your wallet passphrase to unlock the wallet. این عملیت نیاز عبارت عبور پنجره شما دارد برای رمز گشایی آن - + Unlock wallet تکرار عبارت عبور نو - + This operation needs your wallet passphrase to decrypt the wallet. این عملیت نیاز عبارت عبور شما دارد برای رمز بندی آن - + Decrypt wallet رمز بندی پنجره - + Change passphrase تغییر عبارت عبور - + Enter the old and new passphrase to the wallet. عبارت عبور نو و قدیم در پنجره وارد کنید - + Confirm wallet encryption تایید رمز گذاری - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - هشدار اگر شما روی پنجره رمز بگذارید و عبارت عبور فراموش کنید همه بیتکویینس شما گم می کنید. متماینید کن که می خواهید رمز بگذارید + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + هشدار: اگر wallet رمزگذاری شود و شما passphrase را گم کنید شما همه اطلاعات casinocoin را از دست خواهید داد. - - + + Are you sure you wish to encrypt your wallet? + آیا اطمینان دارید که می خواهید wallet رمزگذاری شود؟ + + + + 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. + + + + + + Warning: The Caps Lock key is on! + هشدار: Caps lock key روشن است + + + + Wallet encrypted تغییر عبارت عبور - - Bitcoin 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. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. Biticon هم اکنون بسته می‌شود تا فرایند رمزگذاری را تمام کند. به خاطر داشته باشید که رمزگذاری کیف پولتان نمی‌تواند به طور کامل بیتیکون‌های شما را در برابر دزدیده شدن توسط بدافزارهایی که رایانه شما را آلوده می‌کنند، محافظت نماید. - - - Warning: The Caps Lock key is on. - هشدار: کلید حروف بزرگ روشن است. - - - - - - + + + + Wallet encryption failed عبارت عبور نو و قدیم در پنجره وارد کنید - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. تنا موفق رمز بندی پنجره ناشی از خطای داخل شد. پنجره شما مرز بندی نشده است - - + + The supplied passphrases do not match. عبارت عبور عرضه تطابق نشد - + Wallet unlock failed نجره رمز گذار شد - - - + + + The passphrase entered for the wallet decryption was incorrect. اموفق رمز بندی پنجر - + Wallet decryption failed ناموفق رمز بندی پنجره - - Wallet passphrase was succesfully changed. - عبارت عبور با موفقیت تغییر شد + + Wallet passphrase was successfully changed. + wallet passphrase با موفقیت تغییر یافت BitcoinGUI - - Bitcoin Wallet - پنجره بیتکویین - - - + Sign &message... - + امضا و پیام - - Show/Hide &Bitcoin - - - - + Synchronizing with network... همگام سازی با شبکه ... - + &Overview بررسی اجمالی - + Show general overview of wallet نمای کلی پنجره نشان بده - + &Transactions - &amp;معاملات + &معاملات - + Browse transaction history نمایش تاریخ معاملات - - &Address Book - دفتر آدرس - - - + Edit the list of stored addresses and labels ویرایش لیست آدرسها و بر چسب های ذخیره ای - - &Receive coins - در یافت سکه - - - + Show the list of addresses for receiving payments نمایش لیست آدرس ها برای در یافت پر داخت ها - - &Send coins - رسال سکه ها - - - - Prove you control an address - اثبات کنید که روی یک نشانی کنترل دارید - - - + E&xit خروج - + Quit application خروج از برنامه - - &About %1 - &حدود%1 - - - - Show information about Bitcoin + + Show information about CasinoCoin نمایش اطلاعات در مورد بیتکویین - + About &Qt درباره &Qt - + Show information about Qt نمایش اطلاعات درباره Qt - + &Options... تنظیمات... - + &Encrypt Wallet... - + رمزگذاری wallet - + &Backup Wallet... - + پشتیبان گیری از wallet - + &Change Passphrase... - - - - - ~%n block(s) remaining - + تغییر Passphrase - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... - &;صادرات - - - - Send coins to a Bitcoin address + + Reindexing blocks on disk... - - Modify configuration options for Bitcoin - + + Send coins to a CasinoCoin address + سکه ها را به آدرس bitocin ارسال کن - - Show or hide the Bitcoin window - + + Modify configuration options for CasinoCoin + انتخابهای پیکربندی را برای casinocoin اصلاح کن - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - رمز بندی یا رمز گشایی پنجره - - - + Backup wallet to another location - + نسخه پیشتیبان wallet را به محل دیگر انتقال دهید - + Change the passphrase used for wallet encryption عبارت عبور رمز گشایی پنجره تغییر کنید - + &Debug window - + اشکال زدایی از صفحه - + Open debugging and diagnostic console - + کنسول اشکال زدایی و تشخیص را باز کنید - + &Verify message... + بازبینی پیام + + + + + CasinoCoin + یت کویین + + + + Wallet + wallet + + + + &Send - - Verify a message signature + + &Receive - + + &Addresses + + + + + &About CasinoCoin + در مورد casinocoin + + + + &Show / Hide + &نمایش/ عدم نمایش + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File فایل - + &Settings تنظیمات - + &Help کمک - + Tabs toolbar نوار ابزار زبانه ها - - Actions toolbar - نوار ابزار عملیت - - - - + + [testnet] آزمایش شبکه - - - Bitcoin client - + + CasinoCoin client + مشتری CasinoCoin - - %n active connection(s) to Bitcoin network + + %n active connection(s) to CasinoCoin network در صد ارتباطات فعال بیتکویین با شبکه %n - - Downloaded %1 blocks of transaction history. - دانلود بلوکهای معملات %1 - - - - %n second(s) ago - %n بعد از چند دقیقه - - - - %n minute(s) ago - %n بعد از چند دقیقه - - - - %n hour(s) ago - %n بعد از چند دقیقه - - - - %n day(s) ago - %n بعد از چند روزز + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date تا تاریخ - + Catching up... ابتلا به بالا - - Last received block was generated %1. - خرین بلوک در یافت شده تولید شده بود %1 - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - این معامله از اندازه محدوده بیشتر است. شما می توانید آد را با دستمزد 1% بفرستید که شامل گره معامله شما می باشد و به شبکه های اینترنتی کمک خواهد کردو آیا شما می خواهید این پول پر داخت%1 - - - + Confirm transaction fee - + هزینه تراکنش را تایید کنید - + Sent transaction معامله ارسال شده - + Incoming transaction معامله در یافت شده - + Date: %1 Amount: %2 Type: %3 @@ -583,992 +643,1201 @@ Address: %4 آدرس %4 - + + + URI handling + مدیریت URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI قابل تحلیل نیست. این خطا ممکن است به دلیل ادرس CASINOCOIN اشتباه یا پارامترهای اشتباه URI رخ داده باشد + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> زمایش شبکهه - + Wallet is <b>encrypted</b> and currently <b>locked</b> زمایش شبکه - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + خطا روی داده است. CasinoCoin نمی تواند بدون مشکل ادامه دهد و باید بسته شود ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - دیسپلی - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - زیر بخش پیش فرض در واسط انتخاب کنید و سکه ها ارسال کنید - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + پیام شبکه EditAddressDialog - + Edit Address اصلاح آدرس - + &Label بر چسب - + The label associated with this address book entry بر چسب با دفتر آدرس ورود مرتبط است - + &Address آدرس - + The address associated with this address book entry. This can only be modified for sending addresses. آدرس با دفتر آدرس ورودی مرتبط است. این فقط در مورد آدرسهای ارسال شده است - + New receiving address آدرس در یافت نو - + New sending address آدرس ارسال نو - + Edit receiving address اصلاح آدرس در یافت - + Edit sending address اصلاح آدرس ارسال - + The entered address "%1" is already in the address book. %1آدرس وارد شده دیگر در دفتر آدرس است - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + آدرس وارد شده %1 یک ادرس صحیح casinocoin نیست - + Could not unlock wallet. رمز گشایی پنجره امکان پذیر نیست - + New key generation failed. کلید نسل جدید ناموفق است - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + نسخه - + Usage: ستفاده : - - options - + + command-line options + انتخابها برای خطوط دستور command line - + UI options - + انتخابهای UI - + Set language, for example "de_DE" (default: system locale) - + زبان را تنظیم کنید برای مثال "de_DE" (پیش فرض: system locale) - + Start minimized شروع حد اقل - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - دستمزد&amp;پر داخت معامله - - - - Main - صلی - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - نرخ اختیاری تراکنش هر کیلوبایت که به شما کمک می‌کند اطمینان پیدا کنید که تراکنش‌ها به سرعت پردازش می‌شوند. بیشتر تراکنش‌ها ۱ کیلوبایت هستند. نرخ 0.01 پیشنهاد می‌شود. - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - آدرس از دفتر انتخاب کنید - - - - Alt+A - Alt+A - - - - Paste address from clipboard - آدرس از تخته رسم گیره دار پست کنید - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - پیامی را که می‌خواهید امضا کنید در اینجا وارد کنید - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - روی «امضای پیام» کلیک کنید تا امضا را دریافت نمایید - - - - Sign a message to prove you own this address - یک پیام را امضا کنید تا ثابت کنید صاحب این نشانی هستید - - - - &Sign Message - &امضای پیام - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - آدرس بیتکویین وارد کنید (bijvoorbeeld: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - خطا در امضا - - - - %1 is not a valid address. - %1 یک نشانی معتبر نیست. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - کلید خصوصی برای %1 در دسترس نیست. - - - - Sign failed - امضا موفق نبود - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - درگاه با استفاده از - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - اتوماتیک باز کردن بندر بیتکویین در روتر . این فقط در مواردی می باشد که روتر با کمک یو پ ن پ کار می کند - - - - &Connect through SOCKS4 proxy: - ارتباط با توسط - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - وسل به شبکه بیتکویین با توسط - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - درس پروکسی - - - - Port of the proxy (e.g. 1234) - ورت پروکسی + نمایش صفحه splash در STARTUP (پیش فرض:1) OptionsDialog - + Options اصلی + + + &Main + اصلی + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + دستمزد&پر داخت معامله + + + + Automatically start CasinoCoin after logging in to the system. + در زمان ورود به سیستم به صورت خودکار casinocoin را اجرا کن + + + + &Start CasinoCoin on system login + اجرای casinocoin در زمان ورود به سیستم + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + شبکه + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + اتوماتیک باز کردن بندر بیتکویین در روتر . این فقط در مواردی می باشد که روتر با کمک یو پ ن پ کار می کند + + + + Map port using &UPnP + درگاه با استفاده از + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + اتصال به شبکه CASINOCOIN از طریق پراکسی ساکس (برای مثال وقتی از طریق نرم افزار TOR متصل می شوید) + + + + &Connect through SOCKS proxy: + اتصال با پراکسی SOCKS + + + + Proxy &IP: + پراکسی و آی.پی. + + + + IP address of the proxy (e.g. 127.0.0.1) + درس پروکسی + + + + &Port: + درگاه + + + + Port of the proxy (e.g. 9050) + درگاه پراکسی (مثال 9050) + + + + SOCKS &Version: + SOCKS و نسخه + + + + SOCKS version of the proxy (e.g. 5) + نسخه SOCKS از پراکسی (مثال 5) + + + + &Window + صفحه + + + + Show only a tray icon after minimizing the window. + tray icon را تنها بعد از کوچک کردن صفحه نمایش بده + + + + &Minimize to the tray instead of the taskbar + حد اقل رساندن در جای نوار ابزار ها + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + حد اقل رساندن در جای خروج بر نامه وقتیکه پنجره بسته است.وقتیکه این فعال است برنامه خاموش می شود بعد از انتخاب دستور خاموش در منیو + + + + M&inimize on close + کوچک کردن صفحه در زمان بستن + + + + &Display + نمایش + + + + User Interface &language: + میانجی کاربر و زبان + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + زبان میانجی کاربر می تواند در اینجا تنظیم شود. این تنظیمات بعد از شروع دوباره RESTART در CASINOCOIN اجرایی خواهند بود. + + + + &Unit to show amounts in: + واحد برای نمایش میزان وجوه در: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + بخش فرعی پیش فرض را برای نمایش میانجی و زمان ارسال سکه ها مشخص و انتخاب نمایید + + + + Whether to show CasinoCoin addresses in the transaction list or not. + تا آدرسهای bITCOIN در فهرست تراکنش نمایش داده شوند یا نشوند. + + + + &Display addresses in transaction list + نمایش آدرسها در فهرست تراکنش + + + + &OK + تایید + + + + &Cancel + رد + + + + &Apply + انجام + + + + default + پیش فرض + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + هشدار + + + + + This setting will take effect after restarting CasinoCoin. + این تنظیمات پس از اجرای دوباره CasinoCoin اعمال می شوند + + + + The supplied proxy address is invalid. + آدرس پراکسی داده شده صحیح نیست + OverviewPage - + Form تراز - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + اطلاعات نمایش داده شده روزآمد نیستند.wallet شما به صورت خودکار با شبکه casinocoin بعد از برقراری اتصال روزآمد می شود اما این فرایند هنوز کامل نشده است. - + Balance: راز: - - Number of transactions: - تعداد معامله - - - + Unconfirmed: تایید نشده - + Wallet - + wallet - + + Immature: + نابالغ + + + + Mined balance that has not yet matured + بالانس/تتمه حساب استخراج شده، نابالغ است /تکمیل نشده است + + + <b>Recent transactions</b> اخرین معاملات&lt - + Your current balance تزار جاری شما - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance تعداد معاملات که تایید شده ولی هنوز در تزار جاری شما بر شمار نرفته است - - Total number of transactions in wallet - تعداد معاملات در صندوق - - - - + + out of sync + روزآمد نشده + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - + دیالوگ QR CODE - - QR Code - کد QR - - - + Request Payment درخواست پرداخت - + Amount: مقدار: - - BTC - BTC - - - + Label: برچسب: - + Message: پیام - + &Save As... &ذخیره به عنوان... - + Error encoding URI into QR Code. - + خطا در زمان رمزدار کردن URI در کد QR - + + The entered amount is invalid, please check. + میزان وجه وارد شده صحیح نیست، لطفا بررسی نمایید + + + Resulting URI too long, try to reduce the text for label / message. - + URI ذکر شده بسیار طولانی است، متن برچسب/پیام را کوتاه کنید - + Save QR Code - + ذخیره کد QR - + PNG Images (*.png) - + تصاویر با فرمت PNG (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + نام مشتری - - - - - - - - - + + + + + + + + + + N/A - + - - + Client version - + نسخه مشتری - + &Information - + اطلاعات - - Client - + + Using OpenSSL version + استفاده از نسخه OPENSSL - + Startup time - + زمان آغاز STARTUP - + Network - + شبکه - + Number of connections - + تعداد اتصالات - + On testnet - + در testnetکها - + Block chain - + زنجیره بلاک - + Current number of blocks - + تعداد کنونی بلاکها - + Estimated total blocks - + تعداد تخمینی بلاکها - + Last block time - + زمان آخرین بلاک - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + باز کردن - + + Command-line options + گزینه های command-line + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + پیام راهنمای CasinoCoin-Qt را برای گرفتن فهرست گزینه های command-line نشان بده + + + + &Show + نمایش + + + &Console - + کنسول - + Build date - + ساخت تاریخ - + + CasinoCoin - Debug window + صفحه اشکال زدایی CasinoCoin + + + + CasinoCoin Core + هسته CasinoCoin + + + + Debug log file + فایلِ لاگِ اشکال زدایی + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + فایلِ لاگِ اشکال زدایی CasinoCoin را از دایرکتوری جاری داده ها باز کنید. این عملیات ممکن است برای فایلهای لاگِ حجیم طولانی شود. + + + Clear console - + پاکسازی کنسول - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + به کنسول CasinoCoin RPC خوش آمدید - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + دکمه های بالا و پایین برای مرور تاریخچه و Ctrl-L برای پاکسازی صفحه - + Type <b>help</b> for an overview of available commands. - + با تایپ عبارت HELP دستورهای در دسترس را مرور خواهید کرد SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins ارسال سکه ها - + Send to multiple recipients at once ارسال چندین در یافت ها فورا - - &Add Recipient - + + Add &Recipient + اضافه کردن دریافت کننده - + Remove all transaction fields پاک کردن تمام ستون‌های تراکنش - + Clear &All - + پاکسازی همه - + Balance: تزار : - + 123.456 BTC 123.456 بتس - + Confirm the send action عملیت دوم تایید کنید - - &Send + + S&end &;ارسال - + <b>%1</b> to %2 (%3) (%3) تا <b>%1</b> درصد%2 - + Confirm send coins ارسال سکه ها تایید کنید - + Are you sure you want to send %1? %1شما متماینید که می خواهید 1% ارسال کنید ؟ - + and و - - The recepient address is not valid, please recheck. - آدرس در یافت دو باره چک کنید + + The recipient address is not valid, please recheck. + آدرس گیرنده نادرست است، لطفا دوباره بررسی کنید. - + The amount to pay must be larger than 0. مبلغ پر داخت باید از 0 بیشتر باشد - + The amount exceeds your balance. - + میزان وجه از بالانس/تتمه حساب شما بیشتر است - + The total exceeds your balance when the %1 transaction fee is included. - + کل میزان وجه از بالانس/تتمه حساب شما بیشتر می شود وقتی %1 هزینه تراکنش نیز به ین میزان افزوده می شود - + Duplicate address found, can only send to each address once per send operation. + آدرس تکراری یافت شده است، در زمان انجام عملیات به هر آدرس تنها یکبار می توانید اطلاعات ارسال کنید + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + خطا: تراکنش تایید نشد. این پیام زمانی روی می دهد که مقداری از سکه های WALLET شما استفاده شده اند برای مثال اگر شما از WALLET.DAT استفاده کرده اید، ممکن است سکه ها استفاده شده باشند اما در اینجا نمایش داده نشوند SendCoinsEntry - + Form تراز - + A&mount: - A&amp;مبلغ : + A&مبلغ : - + Pay &To: - به&amp;پر داخت : + به&پر داخت : - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book برای آدرس بر پسب وارد کنید که در دفتر آدرس اضافه شود - + &Label: - & بر چسب + &بر چسب - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - آدرس برای ارسال پر داخت (bijvoorbeeld: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book اآدرسن ازدفتر آدرس انتخاب کنید - + Alt+A Alt+A - + Paste address from clipboard آدرس از تخته رسم گیره دار پست کنید - + Alt+P Alt+P - + Remove this recipient بر داشتن این در یافت کننده - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - آدرس بیتکویین وارد کنید (bijvoorbeeld: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + آدرس بیتکویین وارد کنید (bijvoorbeeld: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + امضا - امضا کردن /شناسایی یک پیام + + + + &Sign Message + &امضای پیام + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + شما می توانید پیامها را با آدرس خودتان امضا نمایید تا ثابت شود متعلق به شما هستند. مواظب باشید تا چیزی که بدان مطمئن نیستنید را امضا نکنید زیرا حملات فیشینگ در زمان ورود شما به سیستم فریبنده هستند. تنها مواردی را که حاوی اطلاعات دقیق و قابل قبول برای شما هستند را امضا کنید + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + آدرس برای امضا کردن پیام با (برای مثال Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + یک آدرس را از فهرست آدرسها انتخاب کنید + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + آدرس از تخته رسم گیره دار پست کنید + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + پیامی را که می‌خواهید امضا کنید در اینجا وارد کنید + + + + Signature + + + + + Copy the current signature to the system clipboard + این امضا را در system clipboard کپی کن + + + + Sign the message to prove you own this CasinoCoin address + پیام را برای اثبات آدرس CASINOCOIN خود امضا کنید + + + + Sign &Message + + + + + Reset all sign message fields + تنظیم دوباره تمامی فیلدهای پیام + + + + + Clear &All + پاکسازی همه + + + + &Verify Message + تایید پیام + + + + Enter the signing 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. + آدرس/پیام خود را وارد کنید (مطمئن شوید که فاصله بین خطوط، فاصله ها، تب ها و ... را دقیقا کپی می کنید) و سپس امضا کنید تا پیام تایید شود. مراقب باشید که پیام را بیشتر از مطالب درون امضا مطالعه نمایید تا فریب شخص سوم/دزدان اینترنتی را نخورید. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + آدرس برای امضا کردن پیام با (برای مثال Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + پیام را برای اطمنان از ورود به سیستم با آدرس CASINOCOIN مشخص خود،تایید کنید + + + + Verify &Message + + + + + Reset all verify message fields + تنظیم دوباره تمامی فیلدهای پیام تایید شده + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + آدرس بیتکویین وارد کنید (bijvoorbeeld: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + با کلیک بر "امضای پیام" شما یک امضای جدید درست می کنید + + + + Enter CasinoCoin signature + امضای BITOCOIN خود را وارد کنید + + + + + The entered address is invalid. + آدرس وارد شده صحیح نیست + + + + + + + Please check the address and try again. + اطفا آدرس را بررسی کرده و دوباره امتحان کنید + + + + + The entered address does not refer to a key. + آدرس وارد شده با کلید وارد شده مرتبط نیست + + + + Wallet unlock was cancelled. + قفل کردن wallet انجام نشد + + + + Private key for the entered address is not available. + کلید شخصی برای آدرس وارد شده در دسترس نیست + + + + Message signing failed. + پیام امضا کردن انجام نشد + + + + Message signed. + پیام امضا شد + + + + The signature could not be decoded. + امضا نمی تواند رمزگشایی شود + + + + + Please check the signature and try again. + لطفا امضا را بررسی و دوباره تلاش نمایید + + + + The signature did not match the message digest. + امضا با تحلیلِ پیام مطابقت ندارد + + + + Message verification failed. + عملیات شناسایی پیام انجام نشد + + + + Message verified. + پیام شناسایی شد + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + آزمایش شبکه TransactionDesc - - Open for %1 blocks - باز کردن 1% بلوک 1%1 - - - + Open until %1 باز کردن تا%1 - - %1/offline? - %1 انلاین نیست + + %1/offline + %1 آفلاین - + %1/unconfirmed %1 تایید نشده - + %1 confirmations ایید %1 - - <b>Status:</b> - &lt;b&gt;وضعیت :&lt;/b&gt; + + Status + وضعیت + + + + , broadcast through %n node(s) + انتشار از طریق n% گره +انتشار از طریق %n گره - - , has not been successfully broadcast yet - هنوز با مو فقیت ارسال نشده + + Date + تاریخ - - , broadcast through %1 node - ارسال توسط گره %1 + + Source + منبع - - , broadcast through %1 nodes - رسال توسط گره های %1 + + Generated + تولید شده - - <b>Date:</b> - &lt;b&gt;تاریخ :&lt;/b&gt + + + From + فرستنده - - <b>Source:</b> Generated<br> - &lt;b&gt;منبع :&lt;/b&gt; Generated&lt;br&gt + + + + To + گیرنده - - - <b>From:</b> - &lt;b&gt;از:&lt;/b&gt; + + + own address + آدرس شما - - unknown - مشخص نیست + + label + برچسب - - - - <b>To:</b> - &lt;b&gt;به :&lt;/b&gt; + + + + + + Credit + بدهی + + + + matures in %n more block(s) + بلوغ در n% از بیشتر بلاکها +بلوغ در %n از بیشتر بلاکها - - (yours, label: - مال شما ، بر چسب( + + not accepted + غیرقابل قبول - - (yours) - مال شما) ( + + + + + Debit + اعتبار - - - - - <b>Credit:</b> - &lt;b&gt;اعتبار :&lt;/b&gt; + + Transaction fee + هزینه تراکنش - - (%1 matures in %2 more blocks) - (%1 )بالغ در بلوک 2% و بیشتر%2 + + Net amount + هزینه خالص - - (not accepted) - قابل قبول نیست ( ) - - - - - - <b>Debit:</b> - &lt;b&gt;مقدار خالص:&lt;/b&gt; - - - - <b>Transaction fee:</b> - &lt;b&gt;پر داخت معامله :&lt;/b&gt; - - - - <b>Net amount:</b> - &lt;b&gt;مبلغ خالص :&lt;/b&gt; - - - - Message: + + Message پیام - - Comment: - مورد نظر + + Comment + نظر - - Transaction ID: - شماره تراکنش: + + Transaction ID + شناسه کاربری برای تراکنش - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - برای ارسال واحد های تولید شده باید 120 بلوک باشند. هنگامی که بلون ایجاد می شود به شبکه ارسال می شود تا در زنجیر بلوکها اضافه شود. و گر نه بلوک به غیر قابول و غیر ارسال عوض می شود. این اتفاقی می افتد وقتی که همزمان گره دیگر در بلوک ایجاد می شود. + + Generated coins must mature 120 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. + سکه های ایجاد شده باید 120 بلاک را قبل از استفاده بالغ کنند. در هنگام ایجاد بلاک، آن بلاک در شبکه منتشر می شود تا به زنجیره بلاکها بپیوندد. اگر در زنجیره قرار نگیرد، پیام وضعیت به غیرقابل قبول تغییر می بپیابد و قابل استفاده نیست. این مورد معمولا زمانی پیش می آید که گره دیگری به طور همزمان بلاکی را با فاصل چند ثانیه ای از شما ایجاد کند. + + + + Debug information + اشکال زدایی طلاعات + + + + Transaction + تراکنش + + + + Inputs + درونداد + + + + Amount + مبلغ + + + + true + صحیح + + + + false + نادرست + + + + , has not been successfully broadcast yet + هنوز با مو فقیت ارسال نشده + + + + Open for %n more block(s) + + + + + unknown + مشخص نیست TransactionDescDialog - + Transaction details جزییات معاملات - + This pane shows a detailed description of the transaction در این قاب شیشه توصیف دقیق معامله نشان می شود @@ -1576,117 +1845,118 @@ Address: %4 TransactionTableModel - + Date تاریخ - + Type نوع - + Address ایل جدا - + Amount مبلغ - - Open for %n block(s) - بلوک %n باز شده برای + + Open for %n more block(s) + - + Open until %1 از شده تا 1%1 - + Offline (%1 confirmations) افلایین (%1) - + Unconfirmed (%1 of %2 confirmations) تایید نشده (%1/%2) - + Confirmed (%1 confirmations) تایید شده (%1) - - Mined balance will be available in %n more blocks - و بیشتر باشند قابل قابول می شود %n تزار اصلی بعد از اینکه بلوکها + + Mined balance will be available when it matures in %n more block(s) + بالانس/تتمه حساب استخراج شده زمانی که %n از بیشتر بلاکها بالغ شدند در دسترس خواهد بود +بالانس/تتمه حساب استخراج شده زمانی که n% از بیشتر بلاکها بالغ شدند در دسترس خواهد بود - + This block was not received by any other nodes and will probably not be accepted! این بلوک از دیگر گره ها در یافت نشده بدین دلیل شاید قابل قابول نیست - + Generated but not accepted تولید شده ولی قبول نشده - + Received with در یافت با : - + Received from دریافتی از - + Sent to ارسال به : - + Payment to yourself پر داخت به خودتان - + Mined استخراج - + (n/a) (کاربرد ندارد) - + Transaction status. Hover over this field to show number of confirmations. وضعیت معالمه . عرصه که تعداد تایید نشان می دهد - + Date and time that the transaction was received. تاریخ و ساعت در یافت معامله - + Type of transaction. نوع معاملات - + Destination address of transaction. آدرس مقصود معاملات - + Amount removed from or added to balance. مبلغ از تزار شما خارج یا وارد شده @@ -1694,819 +1964,962 @@ Address: %4 TransactionView - - + + All همه - + Today امروز - + This week این هفته - + This month این ماه - + Last month ماه گذشته - + This year امسال - + Range... محدوده - + Received with در یافت با - + Sent to ارسال به - + To yourself به خودتان - + Mined استخراج - + Other یگر - + Enter address or label to search برای جست‌‌وجو نشانی یا برچسب را وارد کنید - + Min amount حد اقل مبلغ - + Copy address کپی آدرس - + Copy label کپی بر چسب - + Copy amount روگرفت مقدار - + + Copy transaction ID + + + + Edit label اصلاح بر چسب - + Show transaction details - + جزئیات تراکنش را نمایش بده - + Export Transaction Data صادرات تاریخ معامله - + Comma separated file (*.csv) Comma فایل جدا - + Confirmed تایید شده - + Date تاریخ - + Type نوع - + Label ر چسب - + Address ایل جدا - + Amount مبلغ - + ID آی دی - + Error exporting خطای صادرت - + Could not write to file %1. تا فایل %1 نمی شود نوشت - + Range: >محدوده - + to به - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - آدرس انتخاب شده در سیستم تخته رسم گیره دار کپی کنید - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - ارسال... + + Send Coins + ارسال سکه ها - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - حد اقل رساندن در جای نوار ابزار ها + + Export the data in the current tab to a file + داده ها نوارِ جاری را به فایل انتقال دهید - - Show only a tray icon after minimizing the window - نمایش فقط نماد سینی بعد از حد اقل رساندن پنجره - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - حد اقل رساندن در جای خروج بر نامه وقتیکه پنجره بسته است.وقتیکه این فعال است برنامه خاموش می شود بعد از انتخاب دستور خاموش در منیو + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version + + CasinoCoin version سخه بیتکویین - + Usage: ستفاده : - - Send command to -server or bitcoind + + Send command to -server or casinocoind ارسال فرمان به سرور یا باتکویین - + List commands لیست فومان ها - + Get help for a command کمک برای فرمان - + Options: تنظیمات - - Specify configuration file (default: bitcoin.conf) - (: bitcoin.confپیش فرض: )فایل تنظیمی خاص + + Specify configuration file (default: casinocoin.conf) + (: casinocoin.confپیش فرض: )فایل تنظیمی خاص - - Specify pid file (default: bitcoind.pid) - (bitcoind.pidپیش فرض : ) فایل پید خاص + + Specify pid file (default: casinocoind.pid) + (casinocoind.pidپیش فرض : ) فایل پید خاص - - Generate coins - سکه های تولید شده - - - - Don't generate coins - تولید سکه ها - - - + Specify data directory دایرکتور اطلاعاتی خاص - + Set database cache size in megabytes (default: 25) - + سایز کَش بانک داده را بر حسب مگابایت تنظیم کنید (پیش فرض:25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + برای اتصالات به <port> (پیش‌فرض: 47950 یا تست‌نت: 17950) گوش کنید - - Specify connection timeout (in milliseconds) - (میلی ثانیه )فاصله ارتباط خاص - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - برای اتصالات به <port> (پیش‌فرض: 8333 یا تست‌نت: 18333) گوش کنید - - - + Maintain at most <n> connections to peers (default: 125) حداکثر <n> اتصال با همکاران برقرار داشته باشید (پیش‌فرض: 125) - - Connect only to the specified node - ارتباط فقط به گره خاص - - - + Connect to a node to retrieve peer addresses, and disconnect - + اتصال به گره برای دریافت آدرسهای قرینه و قطع اتصال - + Specify your own public address - + آدرس عمومی خود را ذکر کنید - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) آستانه برای قطع ارتباط با همکاران بدرفتار (پیش‌فرض: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) مدت زمان به ثانیه برای جلوگیری از همکاران بدرفتار برای اتصال دوباره (پیش‌فرض: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - حداکثر بافر دریافتی در هر اتصال، 1000*<n> (پیش‌فرض: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + در زمان تنظیم درگاه RPX %u در فهرست کردن %s اشکالی رخ داده است - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - حداکثر بافر ارسالی در هر اتصال، 1000*<n> (پیش‌فرض: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + ( 47970پیش فرض :) &lt;poort&gt; JSON-RPC شنوایی برای ارتباطات - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands JSON-RPC قابل فرمانها و - + Run in the background as a daemon and accept commands اجرای در پس زمینه به عنوان شبح و قبول فرمان ها - + Use the test network استفاده شبکه آزمایش - - Output extra debugging information - اطلاعات اشکال‌زدایی اضافی خروجی + + Accept connections from outside (default: 1 if no -proxy or -connect) + پذیرش اتصالات از بیرون (پیش فرض:1 بدون پراکسی یا اتصال) - - Prepend debug output with timestamp - به خروجی اشکال‌زدایی برچسب زمان بزنید - - - - Send trace/debug info to console instead of debug.log file - اطلاعات ردگیری/اشکال‌زدایی را به جای فایل لاگ اشکال‌زدایی به کنسول بفرستید - - - - Send trace/debug info to debugger - اطلاعات ردگیری/اشکال‌زدایی را به اشکال‌زدا بفرستید - - - - Username for JSON-RPC connections - JSON-RPC شناسه برای ارتباطات - - - - Password for JSON-RPC connections - JSON-RPC عبارت عبور برای ارتباطات - - - - Listen for JSON-RPC connections on <port> (default: 8332) - ( 8332پیش فرض :) &lt;poort&gt; JSON-RPC شنوایی برای ارتباطات - - - - Allow JSON-RPC connections from specified IP address - از آدرس آی پی خاص JSON-RPC قبول ارتباطات - - - - Send commands to node running on <ip> (default: 127.0.0.1) - (127.0.0.1پیش فرض: ) &lt;ip&gt; دادن فرمانها برای استفاده گره ها روی - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - (100پیش فرض:)&lt;n&gt; گذاشتن اندازه کلید روی - - - - Rescan the block chain for missing wallet transactions - اسکان مجدد زنجیر بلوکها برای گم والت معامله - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -( نگاه کنید Bitcoin Wiki در SSLتنظیمات ):SSL گزینه های - - - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPCبرای ارتباطات استفاده کنید OpenSSL (https) - - - - Server certificate file (default: server.cert) - (server.certپیش فرض: )گواهی نامه سرور - - - - Server private key (default: server.pem) - (server.pemپیش فرض: ) کلید خصوصی سرور - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - رمز های قابل قبول( TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - - - - - This help message - پیام کمکی - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - رمز گشایی دایرکتور داده ها امکان پذیر نیست. شاید بیت کویین در حال فعال می باشد%s - - - - Bitcoin - یت کویین - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - بار گیری آدرس ها - - - - Error loading blkindex.dat - خطا در بارگیری blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - خطا در بارگیری wallet.dat: کیف پول خراب شده است - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - خطا در بارگیری wallet.dat: کیف پول به ویرایش جدیدتری از Biticon نیاز دارد - - - - Wallet needed to be rewritten: restart Bitcoin to complete - سلام - - - - Error loading wallet.dat - خطا در بارگیری wallet.dat - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - خطا ایجاد معامله اشتباه است - - - - Sending... - ارسال... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - خطا . معامله رد شد.این هنگامی که سکه ها در والت شما هنوز ارسال شده اند ولی شما کپی والت استفاده می کنید و سکه ها روی کپی فرستاده شده اند و به عنوان ارسال شنه مشخص نشده اتفاقی می افتد. - - - - Invalid amount - - - - - Insufficient funds - بود جه نا کافی - - - - Loading block index... - بار گیری شاخص بلوک - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - پر داجت برای هر کیلو بیت برای اضافه به معامله ارسال - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - بار گیری والت - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - اسکان مجدد - - - - Done loading - بار گیری انجام شده است - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + حجم حداکثر تراکنشهای با/کم اهمیت را به بایت تنظیم کنید (پیش فرض:27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + هشدار:paytxfee بسیار بالا تعریف شده است! این هزینه تراکنش است که باید در زمان ارسال تراکنش بپردازید + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + هشدار: تراکنش نمایش داده شده ممکن است صحیح نباشد! شما/یا یکی از گره ها به روزآمد سازی نیاز دارید + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + هشدار: لطفا زمان و تاریخ رایانه خود را تصحیح نمایید! اگر ساعت رایانه شما اشتباه باشد casinocoin ممکن است صحیح کار نکند + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + بستن گزینه ایجاد + + + + Connect only to the specified node(s) + تنها در گره (های) مشخص شده متصل شوید + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + آدرس آی.پی. خود را شناسایی کنید (پیش فرض:1 در زمان when listening وno -externalip) + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + شنیدن هر گونه درگاه انجام پذیر نیست. ازlisten=0 برای اینکار استفاده کیند. + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + قرینه ها را برای جستجوی DNS بیاب (پیش فرض: 1 مگر در زمان اتصال) + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + آدرس نرم افزار تور غلط است %s + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + حداکثر بافر دریافت شده بر اساس اتصال <n>* 1000 بایت (پیش فرض:5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + حداکثر بافر دریافت شده بر اساس اتصال <n>* 1000 بایت (پیش فرض:1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + تنها =به گره ها در شبکه متصا شوید <net> (IPv4, IPv6 or Tor) + + + + Output extra debugging information. Implies all other -debug* options + برونداد اطلاعات اشکال زدایی اضافی. گزینه های اشکال زدایی دیگر رفع شدند + + + + Output extra network debugging information + برونداد اطلاعات اشکال زدایی اضافی برای شبکه + + + + Prepend debug output with timestamp + به خروجی اشکال‌زدایی برچسب زمان بزنید + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + گزینه ssl (به ویکیcasinocoin برای راهنمای راه اندازی ssl مراجعه شود) + + + + Select the version of socks proxy to use (4-5, default: 5) + نسخه ای از پراکسی ساکس را برای استفاده انتخاب کنید (4-5 پیش فرض:5) + + + + Send trace/debug info to console instead of debug.log file + اطلاعات ردگیری/اشکال‌زدایی را به جای فایل لاگ اشکال‌زدایی به کنسول بفرستید + + + + Send trace/debug info to debugger + اطلاعات ردگیری/اشکال‌زدایی را به اشکال‌زدا بفرستید + + + + Set maximum block size in bytes (default: 250000) + حداکثر سایز بلاک بر اساس بایت تنظیم شود (پیش فرض: 250000) + + + + Set minimum block size in bytes (default: 0) + حداقل سایز بلاک بر اساس بایت تنظیم شود (پیش فرض: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + فایل debug.log را در startup مشتری کوچک کن (پیش فرض:1 اگر اشکال زدایی روی نداد) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + (میلی ثانیه )فاصله ارتباط خاص + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + از UPnP برای شناسایی درگاه شنیداری استفاده کنید (پیش فرض:0) + + + + Use UPnP to map the listening port (default: 1 when listening) + از UPnP برای شناسایی درگاه شنیداری استفاده کنید (پیش فرض:1 در زمان شنیدن) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + برای دستیابی به سرویس مخفیانه نرم افزار تور از پراکسی استفاده کنید (پیش فرض:same as -proxy) + + + + Username for JSON-RPC connections + JSON-RPC شناسه برای ارتباطات + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + هشدار: این نسخه قدیمی است، روزآمدسازی مورد نیاز است + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + JSON-RPC عبارت عبور برای ارتباطات + + + + Allow JSON-RPC connections from specified IP address + از آدرس آی پی خاص JSON-RPC قبول ارتباطات + + + + Send commands to node running on <ip> (default: 127.0.0.1) + (127.0.0.1پیش فرض: ) &lt;ip&gt; دادن فرمانها برای استفاده گره ها روی + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + زمانی که بهترین بلاک تغییر کرد، دستور را اجرا کن (%s در cmd با block hash جایگزین شده است) + + + + Upgrade wallet to latest format + wallet را به جدیدترین فرمت روزآمد کنید + + + + Set key pool size to <n> (default: 100) + (100پیش فرض:)&lt;n&gt; گذاشتن اندازه کلید روی + + + + Rescan the block chain for missing wallet transactions + اسکان مجدد زنجیر بلوکها برای گم والت معامله + + + + Use OpenSSL (https) for JSON-RPC connections + JSON-RPCبرای ارتباطات استفاده کنید OpenSSL (https) + + + + Server certificate file (default: server.cert) + (server.certپیش فرض: )گواهی نامه سرور + + + + Server private key (default: server.pem) + (server.pemپیش فرض: ) کلید خصوصی سرور + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + رمز های قابل قبول( TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + پیام کمکی + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + امکان اتصال به %s از این رایانه وجود ندارد ( bind returned error %d, %s) + + + + Connect through socks proxy + اتصال از طریق پراکسی ساکس + + + + Allow DNS lookups for -addnode, -seednode and -connect + به DNS اجازه بده تا برای addnode ، seednode و اتصال جستجو کند + + + + Loading addresses... + بار گیری آدرس ها + + + + Error loading wallet.dat: Wallet corrupted + خطا در بارگیری wallet.dat: کیف پول خراب شده است + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + خطا در بارگیری wallet.dat: کیف پول به ویرایش جدیدتری از Biticon نیاز دارد + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + سلام + + + + Error loading wallet.dat + خطا در بارگیری wallet.dat + + + + Invalid -proxy address: '%s' + آدرس پراکسی اشتباه %s + + + + Unknown network specified in -onlynet: '%s' + شبکه مشخص شده غیرقابل شناسایی در onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + نسخه پراکسی ساکس غیرقابل شناسایی درخواست شده است: %i + + + + Cannot resolve -bind address: '%s' + آدرس قابل اتصال- شناسایی نیست %s + + + + Cannot resolve -externalip address: '%s' + آدرس خارجی قابل اتصال- شناسایی نیست %s + + + + Invalid amount for -paytxfee=<amount>: '%s' + میزان وجه اشتباه برای paytxfee=<میزان وجه>: %s + + + + Invalid amount + میزان وجه اشتباه + + + + Insufficient funds + بود جه نا کافی + + + + Loading block index... + بار گیری شاخص بلوک + + + + Add a node to connect to and attempt to keep the connection open + به اتصال یک گره اضافه کنید و اتصال را باز نگاه دارید + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + اتصال به %s از این رایانه امکان پذیر نیست. CasinoCoin احتمالا در حال اجراست. + + + + Fee per KB to add to transactions you send + پر داجت برای هر کیلو بیت برای اضافه به معامله ارسال + + + + Loading wallet... + بار گیری والت + + + + Cannot downgrade wallet + امکان تنزل نسخه در wallet وجود ندارد + + + + Cannot write default address + آدرس پیش فرض قابل ذخیره نیست + + + + Rescanning... + اسکان مجدد + + + + Done loading + بار گیری انجام شده است + + + + To use the %s option + برای استفاده از %s از انتخابات + + + Error - + خطا - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - هشدار: تاریخ و ساعت کامپیوتر شما چک کنید. اگر ساعت درست نیست بیتکویین مناسب نخواهد کار کرد + %s، شما باید یک rpcpassword را در فایل پیکربندی تنظیم کنید :⏎%s⏎ اگر فایل ایجاد نشد، یک فایل فقط متنی ایجاد کنید. + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index 01958e8..1730d08 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -3,1232 +3,1271 @@ AboutDialog - - About Bitcoin + + About CasinoCoin در مورد بیتکویین - - <b>Bitcoin</b> version - <b>Bitcoin</b> version + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> version - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + Copyright + + + + + The CasinoCoin developers + + AddressBookPage - + Address Book - + دفترچه آدرس - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - - - - + Double-click to edit address or label - + برای ویرایش آدرس/برچسب دوبار کلیک نمایید - + Create a new address - + یک آدرس جدید بسازید - + Copy the currently selected address to the system clipboard - + آدرس انتخاب شده را در کلیپ بوردِ سیستم کپی کنید - + &New Address + و آدرس جدید + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - + &Copy Address - + و کپی آدرس - + Show &QR Code + نشان و کد QR + + + + Sign a message to prove you own a CasinoCoin address - - Sign a message to prove you own this address + + Sign &Message - - &Sign Message + + Delete the currently selected address from the list - - Delete the currently selected address from the list. Only sending addresses can be deleted. + + Export the data in the current tab to a file + صدور داده نوار جاری به یک فایل + + + + &Export - + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete + و حذف + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - + Copy &Label - + کپی و برچسب - + &Edit + و ویرایش + + + + Send &Coins - + Export Address Book Data - + انتقال اطلاعات دفترچه آدرس - + Comma separated file (*.csv) - + سی.اس.وی. (فایل جداگانه دستوری) - + Error exporting - + صدور پیام خطا - + Could not write to file %1. - + قابل کپی در فایل نیست %1 AddressTableModel - + Label - + برچسب - + Address - + آدرس - + (no label) - + (برچسب ندارد) AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase - + رمز/پَس فرِیز را وارد کنید - + New passphrase - + رمز/پَس فرِیز جدید را وارد کنید - + Repeat new passphrase - + رمز/پَس فرِیز را دوباره وارد کنید - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - + رمز/پَس فرِیز جدید را در wallet وارد کنید. برای انتخاب رمز/پَس فرِیز از 10 کاراکتر تصادفی یا بیشتر و یا هشت کلمه یا بیشتر استفاده کنید. - + Encrypt wallet - + wallet را رمزگذاری کنید - + This operation needs your wallet passphrase to unlock the wallet. - + برای انجام این عملکرد به رمز/پَس فرِیزِwallet نیاز است تا آن را از حالت قفل درآورد. - + Unlock wallet - + باز کردن قفل wallet - + This operation needs your wallet passphrase to decrypt the wallet. - + برای کشف رمز wallet، به رمز/پَس فرِیزِwallet نیاز است. - + Decrypt wallet - + کشف رمز wallet - + Change passphrase - + تغییر رمز/پَس فرِیز - + Enter the old and new passphrase to the wallet. - + رمز/پَس فرِیزِ قدیم و جدید را در wallet وارد کنید - + Confirm wallet encryption + رمزگذاری wallet را تایید کنید + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? + + Are you sure you wish to encrypt your wallet? - - + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted - + تایید رمزگذاری - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin برای اتمام فرایند رمزگذاری بسته خواهد شد. به خاطر داشته باشید که رمزگذاری WALLET شما، کامپیوتر شما را از آلودگی به بدافزارها مصون نمی دارد. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed - + رمزگذاری تایید نشد - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + رمزگذاری به علت خطای داخلی تایید نشد. wallet شما رمزگذاری نشد - - + + The supplied passphrases do not match. - + رمزهای/پَس فرِیزهایِ وارد شده با هم تطابق ندارند - + Wallet unlock failed - + قفل wallet باز نشد - - - + + + The passphrase entered for the wallet decryption was incorrect. - + رمزهای/پَس فرِیزهایِ وارد شده wallet برای کشف رمز اشتباه است. - + Wallet decryption failed - + کشف رمز wallet انجام نشد - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. BitcoinGUI - - Bitcoin Wallet - - - - + Sign &message... - + امضا و پیام - - Show/Hide &Bitcoin - - - - + Synchronizing with network... - + به روز رسانی با شبکه... - + &Overview - + و بازبینی - + Show general overview of wallet - + نمای کلی از wallet را نشان بده - + &Transactions - + و تراکنش - + Browse transaction history - + تاریخچه تراکنش را باز کن - - &Address Book - - - - + Edit the list of stored addresses and labels - + فهرست آدرسها و برچسبهای ذخیره شده را ویرایش کن - - &Receive coins - - - - + Show the list of addresses for receiving payments - + فهرست آدرسها را برای دریافت وجه نشان بده - - &Send coins - - - - - Prove you control an address - - - - + E&xit - + خروج - + Quit application - + از "درخواست نامه"/ application خارج شو - - &About %1 - + + Show information about CasinoCoin + اطلاعات در مورد CasinoCoin را نشان بده - - Show information about Bitcoin - - - - + About &Qt - + درباره و QT - + Show information about Qt - + نمایش اطلاعات درباره QT - + &Options... - + و انتخابها - + &Encrypt Wallet... - + و رمزگذاری wallet - + &Backup Wallet... - + و گرفتن نسخه پیشتیبان از wallet - + &Change Passphrase... - - - - - ~%n block(s) remaining - + تغییر رمز/پَس فرِیز - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... + + Reindexing blocks on disk... - - Send coins to a Bitcoin address + + Send coins to a CasinoCoin address - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + اصلاح انتخابها برای پیکربندی CasinoCoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - - - - + Backup wallet to another location - + گرفتن نسخه پیشتیبان در آدرسی دیگر - + Change the passphrase used for wallet encryption - + رمز مربوط به رمزگذاریِ wallet را تغییر دهید - + &Debug window - + Open debugging and diagnostic console - + &Verify message... - - Verify a message signature + + + CasinoCoin + casinocoin + + + + Wallet + کیف پول + + + + &Send - + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + &در مورد بیتکویین + + + + &Show / Hide + &نمایش/ عدم نمایش و + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File - + و فایل - + &Settings - + و تنظیمات - + &Help - + و راهنما - + Tabs toolbar - + نوار ابزار - - Actions toolbar - - - - - + + [testnet] + [testnet] + + + + CasinoCoin client + مشتری casinocoin + + + + %n active connection(s) to CasinoCoin network + %n ارتباط فعال به شبکه CasinoCoin +%n ارتباط فعال به شبکه CasinoCoin + + + + No block source available... - - - Bitcoin client + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. - - %n active connection(s) to Bitcoin network + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) - - Downloaded %1 blocks of transaction history. + + %1 behind - - - %n second(s) ago - - - - - %n minute(s) ago - - - - - %n hour(s) ago - - - - - %n day(s) ago - + + + Last received block was generated %1 ago. + - + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date - + روزآمد - + Catching up... - + در حال روزآمد سازی.. - - Last received block was generated %1. - - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - - - - + Confirm transaction fee - + Sent transaction - + ارسال تراکنش - + Incoming transaction - + تراکنش دریافتی - + Date: %1 Amount: %2 Type: %3 Address: %4 + تاریخ: %1⏎ میزان وجه : %2⏎ نوع: %3⏎ آدرس: %4⏎ + + + + + + URI handling - + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - + wallet رمزگذاری شد و در حال حاضر از حالت قفل در آمده است - + Wallet is <b>encrypted</b> and currently <b>locked</b> - + wallet رمزگذاری شد و در حال حاضر قفل است - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + هشدار شبکه EditAddressDialog - + Edit Address - + ویرایش آدرسها - + &Label - + و برچسب - + The label associated with this address book entry - + برچسب مربوط به این دفترچه آدرس - + &Address - + و آدرس - + The address associated with this address book entry. This can only be modified for sending addresses. - + برچسب مربوط به این دفترچه آدرس و تنها ب - + New receiving address - + آدرسِ دریافت کننده جدید - + New sending address - + آدرس ارسال کننده جدید - + Edit receiving address - + ویرایش آدرسِ دریافت کننده - + Edit sending address - + ویرایش آدرسِ ارسال کننده - + The entered address "%1" is already in the address book. - + آدرس وارد شده %1 قبلا به فهرست آدرسها اضافه شده بوده است. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + آدرس وارد شده "%1" یک آدرس صحیح برای casinocoin نسشت - + Could not unlock wallet. - + عدم توانیی برای قفل گشایی wallet - + New key generation failed. - + عدم توانیی در ایجاد کلید جدید - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + نسخه - + Usage: + میزان استفاده: + + + + command-line options - - options - - - - + UI options - + Set language, for example "de_DE" (default: system locale) - + Start minimized - + Show splash screen on startup (default: 1) - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - - - - - Main - - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - - &Connect through SOCKS4 proxy: - - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - - - - - Port of the proxy (e.g. 1234) - - - OptionsDialog - + Options + انتخاب/آپشن + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + و نمایش آدرسها در فهرست تراکنش + + + + &OK + و تایید + + + + &Cancel + و رد + + + + &Apply + و به کار گرفتن + + + + default + پیش فرض + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. OverviewPage - + Form - + فرم - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + اطلاعات نمایش داده شده ممکن است روزآمد نباشد. wallet شما به صورت خودکار بعد از برقراری اتصال با شبکه casinocoin به روز می شود اما این فرایند هنوز تکمیل نشده است. - + Balance: - + مانده حساب: - - Number of transactions: - - - - + Unconfirmed: - + تایید نشده - + Wallet + کیف پول + + + + Immature: - + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> - + تراکنشهای اخیر - + Your current balance - + مانده حساب جاری - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - + تعداد تراکنشهایی که نیاز به تایید دارند و هنوز در مانده حساب جاری شما به حساب نیامده اند - - Total number of transactions in wallet - - - - - + + out of sync + خارج از روزآمد سازی + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - - QR Code - - - - + Request Payment - + درخواست وجه - + Amount: - + میزان وجه: - - BTC - - - - + Label: - + برچسب: - + Message: - + پیام: - + &Save As... - + و ذخیره با عنوانِ... - + Error encoding URI into QR Code. - - Resulting URI too long, try to reduce the text for label / message. + + The entered amount is invalid, please check. - + + Resulting URI too long, try to reduce the text for label / message. + متن وارد شده طولانی است، متنِ برچسب/پیام را کوتاه کنید + + + Save QR Code - + PNG Images (*.png) - + تصاویر با فرمت PNG +(*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Number of connections - + On testnet - + Block chain - + Current number of blocks - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + به کنسول آر.پی.سی. CASINOCOIN خوش آمدید - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1236,1264 +1275,1647 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - + سکه های ارسالی - + Send to multiple recipients at once + ارسال همزمان به گیرنده های متعدد + + + + Add &Recipient - - &Add Recipient - - - - + Remove all transaction fields - + تمامی فیلدهای تراکنش حذف شوند - + Clear &All - + Balance: - + مانده حساب: - + 123.456 BTC - + 123.456 BTC - + Confirm the send action - + تایید عملیات ارسال - - &Send - + + S&end + و ارسال - + <b>%1</b> to %2 (%3) - + %1 به %2 (%3) - + Confirm send coins - + تایید ارسال سکه ها - + Are you sure you want to send %1? - + شما مطمئن هستید که می خواهید %1 را ارسال کنید؟ - + and + و + + + + The recipient address is not valid, please recheck. - - The recepient address is not valid, please recheck. - - - - + The amount to pay must be larger than 0. - + میزان پرداخت باید بیشتر از 0 باشد - + The amount exceeds your balance. - + The total exceeds your balance when the %1 transaction fee is included. - + Duplicate address found, can only send to each address once per send operation. - - Error: Transaction creation failed. + + Error: Transaction creation failed! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + خطا: تراکنش تایید نشد. این خطا ممکن است به این دلیل اتفاق بیافتد که سکه های wallet شما خرج شده باشند مثلا اگر wallet.dat را مپی کرده باشید و سکه های شما در آن کپی استفاده شده باشند اما در اینجا نمایش داده نشده اند. SendCoinsEntry - + Form - + فرم - + A&mount: - + و میزان وجه - + Pay &To: + پرداخت و به چه کسی + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) - - + + Enter a label for this address to add it to your address book - + یک برچسب برای این آدرس بنویسید تا به دفترچه آدرسهای شما اضافه شود - + &Label: - + و برچسب - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - + Choose address from address book - + آدرس از فهرست آدرس انتخاب کنید - + Alt+A - + Alt و A - + Paste address from clipboard - + آدرس را بر کلیپ بورد کپی کنید - + Alt+P - + Alt و P - + Remove this recipient + این گیرنده را حذف کن + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + یک آدرس casinocoin وارد کنید (مثال Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + &Sign Message + و امضای پیام + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + یک آدرس casinocoin وارد کنید (مثال Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + آدرس از فهرست آدرس انتخاب کنید + + + + + Alt+A + Alt و A + + + + Paste address from clipboard + آدرس را بر کلیپ بورد کپی کنید + + + + Alt+P + Alt و P + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + یک آدرس casinocoin وارد کنید (مثال Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + یک آدرس casinocoin وارد کنید (مثال Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] + TransactionDesc - - Open for %1 blocks - - - - + Open until %1 + باز کن تا %1 + + + + %1/offline - - %1/offline? - - - - + %1/unconfirmed - + %1 غیرقابل تایید - + %1 confirmations + %1 تاییدها + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + تاریخ + + + + Source - - <b>Status:</b> + + Generated - + + + From + + + + + + + To + + + + + + own address + + + + + label + برچسب + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + پیام + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + میزان + + + + true + + + + + false + + + + , has not been successfully broadcast yet - + تا به حال با موفقیت انتشار نیافته است + + + + Open for %n more block(s) + - - , broadcast through %1 node - - - - - , broadcast through %1 nodes - - - - - <b>Date:</b> - - - - - <b>Source:</b> Generated<br> - - - - - - <b>From:</b> - - - - + unknown - - - - - - - <b>To:</b> - - - - - (yours, label: - - - - - (yours) - - - - - - - - <b>Credit:</b> - - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - - - - - - - <b>Debit:</b> - - - - - <b>Transaction fee:</b> - - - - - <b>Net amount:</b> - - - - - Message: - - - - - Comment: - - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - + ناشناس TransactionDescDialog - + Transaction details - + جزئیات تراکنش - + This pane shows a detailed description of the transaction - + این بخش جزئیات تراکنش را نشان می دهد TransactionTableModel - + Date - + تاریخ - + Type - + نوع - + Address - + آدرس - + Amount - + میزان وجه - - Open for %n block(s) + + Open for %n more block(s) - + Open until %1 - + باز کن تا %1 - + Offline (%1 confirmations) - + برون خطی (%1 تاییدها) - + Unconfirmed (%1 of %2 confirmations) - + تایید نشده (%1 از %2 تاییدها) - + Confirmed (%1 confirmations) - + تایید شده (%1 تاییدها) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) - + This block was not received by any other nodes and will probably not be accepted! - + این block توسط گره های دیگری دریافت نشده است و ممکن است قبول نشود - + Generated but not accepted - + تولید شده اما قبول نشده است - + Received with - + قبول با - + Received from - + دریافت شده از - + Sent to - + ارسال به - + Payment to yourself - + وجه برای شما - + Mined - + استخراج شده - + (n/a) - + خالی - + Transaction status. Hover over this field to show number of confirmations. - + وضعیت تراکنش. با اشاره به این بخش تعداد تاییدها نمایش داده می شود - + Date and time that the transaction was received. - + زمان و تاریخی که تراکنش دریافت شده است - + Type of transaction. - + نوع تراکنش - + Destination address of transaction. - + آدرس مقصد در تراکنش - + Amount removed from or added to balance. - + میزان وجه کم شده یا اضافه شده به حساب TransactionView - - + + All - + همه - + Today - + امروز - + This week - + این هفته - + This month - + این ماه - + Last month - + ماه گذشته - + This year - + این سال - + Range... - + حدود.. - + Received with - + دریافت با - + Sent to - + ارسال به - + To yourself - + به شما - + Mined - + استخراج شده - + Other - + دیگر - + Enter address or label to search - + آدرس یا برچسب را برای جستجو وارد کنید - + Min amount - + حداقل میزان وجه - + Copy address - + آدرس را کپی کنید - + Copy label - + برچسب را کپی کنید - + Copy amount + میزان وجه کپی شود + + + + Copy transaction ID - + Edit label - + برچسب را ویرایش کنید - + Show transaction details - + Export Transaction Data - + داده های تراکنش را صادر کنید - + Comma separated file (*.csv) - + Comma separated file (*.csv) فایل جداگانه دستوری - + Confirmed - + تایید شده - + Date - + تاریخ - + Type - + نوع - + Label - + برچسب - + Address - + آدرس - + Amount - + میزان - + ID - + شناسه کاربری - + Error exporting - + خطا در ارسال - + Could not write to file %1. - + قابل کپی به فایل نیست %1. - + Range: - + دامنه: - + to - - - - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - + به WalletModel - - Sending... - + + Send Coins + سکه های ارسالی - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file + صدور داده نوار جاری به یک فایل + + + + Backup Wallet - - Show only a tray icon after minimizing the window + + Wallet Data (*.dat) - - M&inimize on close + + Backup Failed - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. bitcoin-core - - Bitcoin version - + + CasinoCoin version + نسخه casinocoin - + Usage: - + میزان استفاده: - - Send command to -server or bitcoind - + + Send command to -server or casinocoind + ارسال دستور به سرور یا casinocoined - + List commands - + فهرست دستورها - + Get help for a command - + درخواست کمک برای یک دستور - + Options: - + انتخابها: - - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + فایل پیکربندیِ را مشخص کنید (پیش فرض: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + فایل pid را مشخص کنید (پیش فرض: casinocoind.pid) - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + دایرکتوری داده را مشخص کن - + Set database cache size in megabytes (default: 25) - + حافظه بانک داده را به مگابایت تنظیم کنید (پیش فرض: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + ارتباطات را در <PORT> بشنوید (پیش فرض: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + نگهداری <N> ارتباطات برای قرینه سازی (پیش فرض:125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + آستانه قطع برای قرینه سازی اشتباه (پیش فرض:100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + تعداد ثانیه ها برای اتصال دوباره قرینه های اشتباه (پیش فرض:86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + ارتباطاتِ JSON-RPC را در <port> گوش کنید (پیش فرض:47970) - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - - - - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + command line و JSON-RPC commands را قبول کنید - + Run in the background as a daemon and accept commands - + به عنوان daemon بک گراند را اجرا کنید و دستورات را قبول نمایید - + Use the test network - - - - - Output extra debugging information - - - - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - - - - - Sending... - - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - + از تستِ شبکه استفاده نمایید - - To use the %s option + + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + برونداد اشکال زدایی با timestamp + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + ارسال اطلاعات پیگیری/خطایابی به کنسول به جای ارسال به فایل debug.log + + + + Send trace/debug info to debugger + ارسال اطاعات خطایابی/پیگیری به سیستم خطایاب + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + تعیین مدت زمان وقفه (time out) به هزارم ثانیه + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + شناسه کاربری برای ارتباطاتِ JSON-RPC + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + رمز برای ارتباطاتِ JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + ارتباطاتِ JSON-RPC را از آدرس آی.پی. مشخصی برقرار کنید. + + + + Send commands to node running on <ip> (default: 127.0.0.1) + دستورات را به گره اجرا شده در<ip> ارسال کنید (پیش فرض:127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + دستور را وقتی بهترین بلاک تغییر کرد اجرا کن (%s در دستور توسط block hash جایگزین شده است) + + + + Upgrade wallet to latest format + wallet را به جدیدترین نسخه روزآمد کنید + + + + Set key pool size to <n> (default: 100) + حجم key pool را به اندازه <n> تنظیم کنید (پیش فرض:100) + + + + Rescan the block chain for missing wallet transactions + زنجیره بلاک را برای تراکنش جا افتاده در WALLET دوباره اسکن کنید + + + + Use OpenSSL (https) for JSON-RPC connections + برای ارتباطاتِ JSON-RPC از OpenSSL (https) استفاده کنید + + + + Server certificate file (default: server.cert) + فایل certificate سرور (پیش فرض server.cert) + + + + Server private key (default: server.pem) + رمز اختصاصی سرور (پیش فرض: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + ciphers قابل قبول (پیش فرض: default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + این پیام راهنما + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + لود شدن آدرسها.. + + + + Error loading wallet.dat: Wallet corrupted + خطا در هنگام لود شدن wallet.dat: Wallet corrupted + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + خطا در هنگام لود شدن wallet.dat. به نسخه جدید Bitocin برای wallet نیاز است. + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + wallet نیاز به بازنویسی دارد. CasinoCoin را برای تکمیل عملیات دوباره اجرا کنید. + + + + Error loading wallet.dat + خطا در هنگام لود شدن wallet.dat + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + میزان اشتباه است for -paytxfee=<amount>: '%s' + + + + Invalid amount + میزان اشتباه است + + + + Insufficient funds + وجوه ناکافی + + + + Loading block index... + لود شدن نمایه بلاکها.. + + + + Add a node to connect to and attempt to keep the connection open + یک گره برای اتصال اضافه کنید و تلاش کنید تا اتصال را باز نگاه دارید + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + هزینه بر اساس کیلو بایت برای اضافه شدن به تراکنشی که ارسال کرده اید + + + + Loading wallet... + wallet در حال لود شدن است... + + + + Cannot downgrade wallet + قابلیت برگشت به نسخه قبلی برای wallet امکان پذیر نیست + + + + Cannot write default address + آدرس پیش فرض قابل ذخیره نیست + + + + Rescanning... + اسکنِ دوباره... + + + + Done loading + اتمام لود شدن + + + + To use the %s option + برای استفاده از %s از اختیارات + + + Error - + خطا - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - + شما باید یک رمز rpcpassword=<password> را در فایل تنظیمات ایجاد کنید⏎ %s ⏎ اگر فایل ایجاد نشده است، آن را با یک فایل "فقط متنی" ایجاد کنید. + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index e9fcf50..09275cf 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -3,122 +3,161 @@ AboutDialog - - About Bitcoin - Tietoa Bitcoinista + + About CasinoCoin + Tietoa CasinoCoinista - - <b>Bitcoin</b> version - <b>Bitcoin</b> versio + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versio - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Developers + +Tämä on kokeellinen ohjelmisto. -This is experimental software. +Levitetään MIT/X11 ohjelmistolisenssin alaisuudessa. Tarkemmat tiedot löytyvät tiedostosta COPYING tai osoitteesta http://www.opensource.org/licenses/mit-license.php. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. - -This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. +Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.openssl.org/), Eric Youngin (eay@cryptsoft.com) kehittämän salausohjelmiston sekä Thomas Bernardin UPnP ohjelmiston. + + + + + Copyright + Tekijänoikeus + + + + The CasinoCoin developers + AddressBookPage - + Address Book Osoitekirja - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Nämä ovat sinun Bitcoin-osoitteesi suoritusten vastaanottamiseen. Voit halutessasi antaa kullekin lähettäjälle eri osoitteen, jotta voit seurata kuka sinulle maksaa. - - - + Double-click to edit address or label Kaksoisnapauta muokataksesi osoitetta tai nimeä - + Create a new address Luo uusi osoite - + Copy the currently selected address to the system clipboard Kopioi valittu osoite leikepöydälle - + &New Address - + &Uusi Osoite - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Nämä ovat CasinoCoin-osoitteesi joihin voit vastaanottaa maksuja. Voit haluta antaa jokaiselle maksajalle omansa, että pystyt seuraamaan keneltä maksut tulevat. + + + &Copy Address - + &Kopioi Osoite - + Show &QR Code Näytä &QR-koodi - - Sign a message to prove you own this address - Allekirjoita viesti millä todistat omistavasi tämän osoitteen + + Sign a message to prove you own a CasinoCoin address + Allekirjoita viesti todistaaksesi, että omistat CasinoCoin-osoitteen - - &Sign Message - &Allekirjoita viesti + + Sign &Message + Allekirjoita &viesti - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Poista valittuna oleva osoite listasta. Vain lähettämiseen käytettäviä osoitteita voi poistaa. + + Delete the currently selected address from the list + Poista valittu osoite listalta - + + Export the data in the current tab to a file + Vie auki olevan välilehden tiedot tiedostoon + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Tarkista viestin allekirjoitus varmistaaksesi, että se allekirjoitettiin tietyllä CasinoCoin-osoitteella + + + + &Verify Message + &Varmista viesti... + + + &Delete &Poista - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Kopioi &Nimi - + &Edit - + &Muokkaa - + + Send &Coins + Lähetä &Rahaa + + + Export Address Book Data Vie osoitekirja - + Comma separated file (*.csv) Comma separated file (*.csv) - + Error exporting Virhe viedessä osoitekirjaa - + Could not write to file %1. Ei voida kirjoittaa tiedostoon %1. @@ -126,17 +165,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Nimi - + Address Osoite - + (no label) (ei nimeä) @@ -144,432 +183,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Tunnuslauseen Dialogi - + Enter passphrase - Anna tunnuslause + Kirjoita tunnuslause - + New passphrase Uusi tunnuslause - + Repeat new passphrase - Toista uusi tunnuslause + Kiroita uusi tunnuslause uudelleen - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Anna lompakolle uusi tunnuslause.<br/>Käytä tunnuslausetta, jossa on ainakin <b>10 satunnaista mekkiä</b> tai <b>kahdeksan sanaa</b>. - + Encrypt wallet Salaa lompakko - + This operation needs your wallet passphrase to unlock the wallet. Tätä toimintoa varten sinun täytyy antaa lompakon tunnuslause sen avaamiseksi. - + Unlock wallet Avaa lompakko - + This operation needs your wallet passphrase to decrypt the wallet. Tätä toimintoa varten sinun täytyy antaa lompakon tunnuslause salauksen purkuun. - + Decrypt wallet Pura lompakon salaus - + Change passphrase Vaihda tunnuslause - + Enter the old and new passphrase to the wallet. Anna vanha ja uusi tunnuslause. - + Confirm wallet encryption - Hyväksy lompakon salaus + Vahvista lompakon salaus - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - VAROITUS: Mikäli salaat lompakkosi ja unohdat tunnuslauseen, <b>MENETÄT LOMPAKON KOKO SISÄLLÖN</b>! -Tahdotko varmasti salata lompakon? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Varoitus: Jos salaat lompakkosi ja menetät tunnuslauseesi, <b>MENETÄT KAIKKI CASINOCOINISI</b>! - - + + Are you sure you wish to encrypt your wallet? + Haluatko varmasti salata lompakkosi? + + + + 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. + TÄRKEÄÄ: Kaikki vanhat lompakon varmuuskopiot pitäisi korvata uusilla suojatuilla varmuuskopioilla. Turvallisuussyistä edelliset varmuuskopiot muuttuvat turhiksi, kun aloitat suojatun lompakon käytön. + + + + + Warning: The Caps Lock key is on! + Varoitus: Caps Lock on käytössä! + + + + Wallet encrypted Lompakko salattu - - Bitcoin 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. - Bitcoin sulkeutuu lopettaakseen salausprosessin. Muista, että salattu lompakko ei täysin suojaa sitä haittaohjelmien aiheuttamilta varkauksilta. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin sulkeutuu lopettaakseen salausprosessin. Muista, että salattukaan lompakko ei täysin suojaa sitä haittaohjelmien aiheuttamilta varkauksilta. - - - Warning: The Caps Lock key is on. - Varoitus: Caps Lock on päällä. - - - - - - + + + + Wallet encryption failed Lompakon salaus epäonnistui - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - Lompakon salaaminen epäonnistui sisäisen virheen vuoksi. Lompakkoa ei salattu. + Lompakon salaaminen epäonnistui sisäisen virheen vuoksi. Lompakkoasi ei salattu. - - + + The supplied passphrases do not match. Annetut tunnuslauseet eivät täsmää. - + Wallet unlock failed Lompakon avaaminen epäonnistui. - - - + + + The passphrase entered for the wallet decryption was incorrect. Annettu tunnuslause oli väärä. - + Wallet decryption failed Lompakon salauksen purku epäonnistui. - - Wallet passphrase was succesfully changed. - Lompakon tunnuslause on vaihdettu. + + Wallet passphrase was successfully changed. + Lompakon tunnuslause vaihdettiin onnistuneesti. BitcoinGUI - - Bitcoin Wallet - Bitcoin-lompakko - - - + Sign &message... - + &Allekirjoita viesti... - - Show/Hide &Bitcoin - Näytä/Kätke &Bitcoin - - - + Synchronizing with network... Synkronoidaan verkon kanssa... - + &Overview &Yleisnäkymä - + Show general overview of wallet - Näyttää kokonaiskatsauksen lompakon tilanteesta + Lompakon tilanteen yleiskatsaus - + &Transactions &Rahansiirrot - + Browse transaction history Selaa rahansiirtohistoriaa - - &Address Book - &Osoitekirja - - - + Edit the list of stored addresses and labels Muokkaa tallennettujen nimien ja osoitteiden listaa - - &Receive coins - &Vastaanota Bitcoineja - - - + Show the list of addresses for receiving payments - Näytä Bitcoinien vastaanottamiseen käytetyt osoitteet + Näytä CasinoCoinien vastaanottamiseen käytetyt osoitteet - - &Send coins - &Lähetä Bitcoineja - - - - Prove you control an address - Todista että hallitset osoitetta - - - + E&xit L&opeta - + Quit application - Lopeta ohjelma + Sulje ohjelma - - &About %1 - &Tietoja %1 + + Show information about CasinoCoin + Näytä tietoa CasinoCoin-projektista - - Show information about Bitcoin - Näytä tietoa Bitcoin-projektista - - - + About &Qt Tietoja &Qt - + Show information about Qt Näytä tietoja QT:ta - + &Options... &Asetukset... - + &Encrypt Wallet... - + &Salaa lompakko... - + &Backup Wallet... - + &Varmuuskopioi Lompakko... - + &Change Passphrase... - - - - - ~%n block(s) remaining - ~%n lohko jäljellä~%n lohkoja jäljellä + &Vaihda Tunnuslause... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Ladattu %1 / %2 lohkoista rahansiirtohistoriasta (%3% suoritettu). + + Importing blocks from disk... + Tuodaan lohkoja levyltä - - &Export... - &Vie... + + Reindexing blocks on disk... + Ladataan lohkoindeksiä... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Lähetä kolikoita CasinoCoin-osoitteeseen - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Muuta CasinoCoinin konfiguraatioasetuksia - - Show or hide the Bitcoin window - Näytä tai piillota Bitcoin-ikkuna - - - - Export the data in the current tab to a file - Vie auki olevan välilehden tiedot tiedostoon - - - - Encrypt or decrypt wallet - Salaa tai poista salaus lompakosta - - - + Backup wallet to another location Varmuuskopioi lompakko toiseen sijaintiin - + Change the passphrase used for wallet encryption Vaihda lompakon salaukseen käytettävä tunnuslause - + &Debug window - + &Testausikkuna - + Open debugging and diagnostic console - + Avaa debuggaus- ja diagnostiikkakonsoli - + &Verify message... - + Varmista &viesti... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Lompakko + + + + &Send + &Lähetä + + + + &Receive + &Vastaanota + + + + &Addresses + &Osoitteet + + + + &About CasinoCoin + &Tietoa CasinoCoinista + + + + &Show / Hide + &Näytä / Piilota + + + + Show or hide the main Window + Näytä tai piilota CasinoCoin-ikkuna + + + + Encrypt the private keys that belong to your wallet + Suojaa yksityiset avaimet, jotka kuuluvat lompakkoosi + + + + Sign messages with your CasinoCoin addresses to prove you own them + Allekirjoita viestisi omalla CasinoCoin -osoitteellasi todistaaksesi, että omistat ne + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Varmista, että viestisi on allekirjoitettu määritetyllä CasinoCoin -osoitteella + + + &File &Tiedosto - + &Settings &Asetukset - + &Help &Apua - + Tabs toolbar Välilehtipalkki - - Actions toolbar - Toimintopalkki - - - - + + [testnet] [testnet] - - - Bitcoin client - Bitcoin-asiakas + + CasinoCoin client + CasinoCoin-asiakas - - %n active connection(s) to Bitcoin network - %n aktiivinen yhteys Bitcoin-verkkoon%n aktiivista yhteyttä Bitcoin-verkkoon + + %n active connection(s) to CasinoCoin network + %n aktiivinen yhteys CasinoCoin-verkkoon%n aktiivista yhteyttä CasinoCoin-verkkoon - - Downloaded %1 blocks of transaction history. - Ladattu %1 lohkoa rahansiirron historiasta. - - - - %n second(s) ago - %n sekunti sitten%n sekuntia sitten - - - - %n minute(s) ago - %n minuutti sitten%n minuuttia sitten - - - - %n hour(s) ago - %n tunti sitten%n tuntia sitten - - - - %n day(s) ago - %n päivä sitten%n päivää sitten + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + Käsitelty %1 lohkoa rahansiirtohistoriasta + + + + %n hour(s) + %n tunti%n tuntia + + + + %n day(s) + + + + + %n week(s) + %n viikko%n viikkoa + + + + %1 behind + + + + + Last received block was generated %1 ago. + Viimeisin vastaanotettu lohko tuotettu %1. + + + + Transactions after this will not yet be visible. + + + + + Error + Virhe + + + + Warning + Varoitus + + + + Information + Tietoa + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Rahansiirtohistoria on ajan tasalla - + Catching up... - Kurotaan kiinni... + Saavutetaan verkkoa... - - Last received block was generated %1. - Viimeisin vastaanotettu lohko tuotettu %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Tämä rahansiirto ylittää kokorajoituksen. Voit siitä huolimatta lähettää sen %1 siirtopalkkion mikä menee solmuille jotka käsittelevät rahansiirtosi tämä auttaa myös verkostoa. Haluatko maksaa siirtopalkkion? - - - + Confirm transaction fee - + Vahvista maksukulu - + Sent transaction Lähetetyt rahansiirrot - + Incoming transaction Saapuva rahansiirto - + Date: %1 Amount: %2 Type: %3 @@ -581,539 +648,485 @@ Tyyppi: %3 Osoite: %4 - + + + URI handling + URI käsittely + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URIa ei voitu jäsentää! Tämä voi johtua kelvottomasta CasinoCoin-osoitteesta tai virheellisistä URI parametreista. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Lompakko on <b>salattu</b> ja tällä hetkellä <b>avoinna</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Lompakko on <b>salattu</b> ja tällä hetkellä <b>lukittuna</b> - - Backup Wallet - Varmuuskopioi lompakko - - - - Wallet Data (*.dat) - Lompakkodata (*.dat) - - - - Backup Failed - Varmuuskopio epäonnistui - - - - There was an error trying to save the wallet data to the new location. - Virhe tallennettaessa lompakkodataa uuteen sijaintiin. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Peruuttamaton virhe on tapahtunut. CasinoCoin ei voi enää jatkaa turvallisesti ja sammutetaan. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Näyttö - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Valitse oletus lisämääre mikä näkyy käyttöliittymässä ja kun lähetät kolikoita - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Verkkohälytys EditAddressDialog - + Edit Address Muokkaa osoitetta - + &Label &Nimi - + The label associated with this address book entry Tähän osoitteeseen liitetty nimi - + &Address &Osoite - + The address associated with this address book entry. This can only be modified for sending addresses. Osoite, joka liittyy tämän osoitekirjan merkintään. Tätä voidaan muuttaa vain lähtevissä osoitteissa. - + New receiving address Uusi vastaanottava osoite - + New sending address Uusi lähettävä osoite - + Edit receiving address Muokkaa vastaanottajan osoitetta - + Edit sending address Muokkaa lähtevää osoitetta - + The entered address "%1" is already in the address book. Osoite "%1" on jo osoitekirjassa. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Antamasi osoite "%1" ei ole validi CasinoCoin-osoite. - + Could not unlock wallet. Lompakkoa ei voitu avata. - + New key generation failed. Uuden avaimen luonti epäonnistui. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versio - + Usage: Käyttö: - - options - + + command-line options + komentorivi parametrit - + UI options - + Käyttöliittymäasetukset - + Set language, for example "de_DE" (default: system locale) Set language, for example "de_DE" (default: system locale) - + Start minimized Käynnistä pienennettynä - + Show splash screen on startup (default: 1) Näytä aloitusruutu käynnistettäessä (oletus: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Asetukset + + + + &Main + &Yleiset + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Maksa rahansiirtopalkkio - - Main - Yleiset + + Automatically start CasinoCoin after logging in to the system. + Käynnistä CasinoCoin kirjautumisen yhteydessä. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Vapaaehtoinen rahansiirtopalkkio per kB auttaa nopeuttamaan siirtoja. Useimmat rahansiirrot ovat 1 kB. 0.01 palkkio on suositeltava. + + &Start CasinoCoin on system login + &Käynnistä CasinoCoin kirjautumisen yhteydessä - - &Start Bitcoin on system login + + Reset all client options to default. - - Automatically start Bitcoin after logging in to the system + + &Reset Options - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + &Verkko - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Voit allekirjoittaa viestit omalla osoitteellasi todistaaksesi että omistat ne. Ole huolellinen, että et allekirjoita mitään epämääräistä, phishing-hyökkääjät voivat huijata sinua allekirjoittamaan luovuttamalla henkilöllisyytesi. Allekirjoita selvitys täysin yksityiskohtaisesti mihin olet sitoutunut. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Avaa CasinoCoin-asiakasohjelman portti reitittimellä automaattisesti. Tämä toimii vain, jos reitittimesi tukee UPnP:tä ja se on käytössä. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Osoite millä viesti allekirjoitetaan (esim. -1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Valitse osoite osoitekirjasta - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Liitä osoite leikepöydältä - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Kirjoita tähän viesti minkä haluat allekirjoittaa - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Klikkaa "Allekirjoita viesti" saadaksesi allekirjoituksen - - - - Sign a message to prove you own this address - Allekirjoita viesti millä todistat omistavasi tämän osoitteen - - - - &Sign Message - &Allekirjoita viesti - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Anna Bitcoin-osoite (esim. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Virhe allekirjoitettaessa - - - - %1 is not a valid address. - %1 ei ole kelvollinen osoite. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Yksityisavain %1 :lle ei ole saatavilla. - - - - Sign failed - Allekirjoittaminen epäonnistui - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Portin uudelleenohjaus &UPnP:llä - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Avaa Bitcoin-asiakasohjelman portti reitittimellä automaattisesti. Tämä toimii vain, jos reitittimesi tukee UPnP:tä ja se on käytössä. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Ota yhteys CasinoCoin-verkkoon SOCKS-proxyn läpi (esimerkiksi kun haluat käyttää Tor-verkkoa). - - &Connect through SOCKS4 proxy: - &Yhdistä SOCKS4-välityspalvelimen kautta: + + &Connect through SOCKS proxy: + &Ota yhteys SOCKS-proxyn kautta: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Yhdistä Bitcoin-verkkoon SOCKS4-välityspalvelimen kautta (esimerkiksi käyttäessä Tor:ia) - - - + Proxy &IP: - + Proxyn &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Välityspalvelimen IP-osoite (esim. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Portti, johon Bitcoin-asiakasohjelma yhdistää (esim. 1234) + + &Port: + &Portti - - - OptionsDialog - - Options - Asetukset + + Port of the proxy (e.g. 9050) + Proxyn Portti (esim. 9050) + + + + SOCKS &Version: + SOCKS &Versio: + + + + SOCKS version of the proxy (e.g. 5) + Proxyn SOCKS-versio (esim. 5) + + + + &Window + &Ikkuna + + + + Show only a tray icon after minimizing the window. + Näytä ainoastaan ilmaisinalueella ikkunan pienentämisen jälkeen. + + + + &Minimize to the tray instead of the taskbar + &Pienennä ilmaisinalueelle työkalurivin sijasta + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Ikkunaa suljettaessa vain pienentää CasinoCoin-ohjelman ikkunan lopettamatta itse ohjelmaa. Kun tämä asetus on valittuna, ohjelman voi sulkea vain valitsemalla Lopeta ohjelman valikosta. + + + + M&inimize on close + P&ienennä suljettaessa + + + + &Display + &Käyttöliittymä + + + + User Interface &language: + &Käyttöliittymän kieli + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Tässä voit määritellä käyttöliittymän kielen. Muutokset astuvat voimaan seuraavan kerran, kun CasinoCoin käynnistetään. + + + + &Unit to show amounts in: + Yksikkö jona casinocoin-määrät näytetään + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Valitse mitä yksikköä käytetään ensisijaisesti casinocoin-määrien näyttämiseen. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Näytetäänkö CasinoCoin-osoitteet rahansiirrot listassa vai ei. + + + + &Display addresses in transaction list + &Näytä osoitteet rahansiirrot listassa + + + + &OK + &OK + + + + &Cancel + &Peruuta + + + + &Apply + &Hyväksy + + + + default + oletus + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Varoitus + + + + + This setting will take effect after restarting CasinoCoin. + Tämä asetus astuu voimaan seuraavalla kerralla, kun CasinoCoin käynnistetään. + + + + The supplied proxy address is invalid. + Antamasi proxy-osoite on virheellinen. OverviewPage - + Form Lomake - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Näytetyt tiedot eivät välttämättä ole ajantasalla. Lompakkosi synkronoituu CasinoCoin-verkon kanssa automaattisesti yhteyden muodostamisen jälkeen, mutta synkronointi on vielä meneillään. - + Balance: Saldo: - - Number of transactions: - Rahansiirtojen lukumäärä: - - - + Unconfirmed: Vahvistamatta: - + Wallet Lompakko - + + Immature: + Epäkypsää: + + + + Mined balance that has not yet matured + Louhittu saldo, joka ei ole vielä kypsynyt + + + <b>Recent transactions</b> <b>Viimeisimmät rahansiirrot</b> - + Your current balance - Tililläsi tällä hetkellä olevien Bitcoinien määrä + Tililläsi tällä hetkellä olevien CasinoCoinien määrä - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Niiden saapuvien rahansiirtojen määrä, joita Bitcoin-verkko ei vielä ole ehtinyt vahvistaa ja siten eivät vielä näy saldossa. + Niiden saapuvien rahansiirtojen määrä, joita CasinoCoin-verkko ei vielä ole ehtinyt vahvistaa ja siten eivät vielä näy saldossa. - - Total number of transactions in wallet - Lompakolla tehtyjen rahansiirtojen yhteismäärä - - - - + + out of sync + Ei ajan tasalla + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - + QR-koodi Dialogi - - QR Code - QR-koodi - - - + Request Payment Vastaanota maksu - + Amount: Määrä: - - BTC - BTC - - - + Label: Tunniste: - + Message: Viesti: - + &Save As... &Tallenna nimellä... - + Error encoding URI into QR Code. - + Virhe käännettäessä URI:a QR-koodiksi. - + + The entered amount is invalid, please check. + Syötetty määrä on virheellinen. Tarkista kirjoitusasu. + + + Resulting URI too long, try to reduce the text for label / message. Tuloksen URI liian pitkä, yritä lyhentää otsikon tekstiä / viestiä. - + Save QR Code - + Tallenna QR-koodi - + PNG Images (*.png) PNG kuvat (*png) @@ -1121,453 +1134,713 @@ Osoite: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Pääteohjelman nimi - - - - - - - - - + + + + + + + + + + N/A - + Ei saatavilla - + Client version - + Pääteohjelman versio - + &Information - + T&ietoa - - Client - + + Using OpenSSL version + Käytössä oleva OpenSSL-versio - + Startup time - + Käynnistysaika - + Network - + Verkko - + Number of connections - + Yhteyksien lukumäärä - + On testnet - + Käyttää testiverkkoa - + Block chain - + Lohkoketju - + Current number of blocks - + Nykyinen Lohkojen määrä - + Estimated total blocks - + Arvioitu lohkojen kokonaismäärä - + Last block time - + Viimeisimmän lohkon aika - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Avaa - + + Command-line options + Komentorivi parametrit + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Näytä CasinoCoin-Qt komentoriviparametrien ohjesivu, jossa on listattuna mahdolliset komentoriviparametrit. + + + + &Show + &Näytä + + + &Console - + &Konsoli - + Build date - + Kääntöpäiväys - + + CasinoCoin - Debug window + CasinoCoin - Debug ikkuna + + + + CasinoCoin Core + CasinoCoin-ydin + + + + Debug log file + Debug lokitiedosto + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Avaa lokitiedosto nykyisestä data-kansiosta. Tämä voi viedä useamman sekunnin, jos lokitiedosto on iso. + + + Clear console - + Tyhjennä konsoli - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Tervetuloa CasinoCoin RPC konsoliin. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Ylös- ja alas-nuolet selaavat historiaa ja <b>Ctrl-L</b> tyhjentää ruudun. - + Type <b>help</b> for an overview of available commands. - + Kirjoita <b>help</b> nähdäksesi yleiskatsauksen käytettävissä olevista komennoista. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Lähetä Bitcoineja + Lähetä CasinoCoineja - + Send to multiple recipients at once Lähetä monelle vastaanottajalle - - &Add Recipient - + + Add &Recipient + Lisää &Vastaanottaja - + Remove all transaction fields Poista kaikki rahansiirtokentät - + Clear &All - + &Tyhjennnä Kaikki - + Balance: Saldo: - + 123.456 BTC 123,456 BTC - + Confirm the send action Vahvista lähetys - - &Send + + S&end &Lähetä - + <b>%1</b> to %2 (%3) <b>%1</b> to %2 (%3) - + Confirm send coins - Hyväksy Bitcoinien lähettäminen + Hyväksy CasinoCoinien lähettäminen - + Are you sure you want to send %1? Haluatko varmasti lähettää %1? - + and ja - - The recepient address is not valid, please recheck. - Vastaanottajan osoite ei kelpaa, ole hyvä ja tarkista + + The recipient address is not valid, please recheck. + Vastaanottajan osoite on virheellinen. Tarkista osoite. - + The amount to pay must be larger than 0. - Maksettavan summan tulee olla suurempi kuin 0 Bitcoinia. + Maksettavan summan tulee olla suurempi kuin 0 CasinoCoinia. - + The amount exceeds your balance. - + Määrä ylittää käytettävissä olevan saldon. - + The total exceeds your balance when the %1 transaction fee is included. - + Kokonaismäärä ylittää saldosi kun %1 maksukulu lisätään summaan. - + Duplicate address found, can only send to each address once per send operation. + Sama osoite toistuu useamman kerran. Samaan osoitteeseen voi lähettää vain kerran per maksu. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Virhe: Rahansiirto hylättiin. Tämä voi tapahtua jos jotkin casinocoineistasi on jo käytetty, esimerkiksi jos olet käyttänyt kopiota wallet.dat-lompakkotiedostosta ja casinocoinit on merkitty käytetyksi vain kopiossa. SendCoinsEntry - + Form Lomake - + A&mount: M&äärä: - + Pay &To: Maksun saaja: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Anna nimi tälle osoitteelle, jos haluat lisätä sen osoitekirjaan - + &Label: &Nimi: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Osoite, johon Bitcoinit lähetetään (esim. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Valitse osoite osoitekirjasta - + Alt+A Alt+A - + Paste address from clipboard Liitä osoite leikepöydältä - + Alt+P Alt+P - + Remove this recipient Poista - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Anna Bitcoin-osoite (esim. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Anna CasinoCoin-osoite (esim. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Allekirjoitukset - Allekirjoita / Varmista viesti + + + + &Sign Message + &Allekirjoita viesti + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Voit allekirjoittaa viestit omalla osoitteellasi todistaaksesi että omistat ne. Ole huolellinen, että et allekirjoita mitään epämääräistä, phishing-hyökkääjät voivat huijata sinua allekirjoittamaan luovuttamalla henkilöllisyytesi. Allekirjoita selvitys täysin yksityiskohtaisesti mihin olet sitoutunut. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Osoite, jolla viesti allekirjoitetaan (esimerkiksi Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Valitse osoite osoitekirjasta + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Liitä osoite leikepöydältä + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Kirjoita tähän viesti minkä haluat allekirjoittaa + + + + Signature + Allekirjoitus + + + + Copy the current signature to the system clipboard + Kopioi tämänhetkinen allekirjoitus leikepöydälle + + + + Sign the message to prove you own this CasinoCoin address + Allekirjoita viesti todistaaksesi, että omistat tämän CasinoCoin-osoitteen + + + + Sign &Message + Allekirjoita &viesti + + + + Reset all sign message fields + Tyhjennä kaikki allekirjoita-viesti-kentät + + + + + Clear &All + &Tyhjennä Kaikki + + + + &Verify Message + &Varmista viesti + + + + Enter the signing 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. + Syötä allekirjoittava osoite, viesti ja allekirjoitus alla oleviin kenttiin varmistaaksesi allekirjoituksen aitouden. Varmista että kopioit kaikki kentät täsmälleen oikein, myös rivinvaihdot, välilyönnit, tabulaattorit, jne. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Osoite, jolla viesti allekirjoitettiin (esimerkiksi Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Tarkista viestin allekirjoitus varmistaaksesi, että se allekirjoitettiin tietyllä CasinoCoin-osoitteella + + + + Verify &Message + + + + + Reset all verify message fields + Tyhjennä kaikki varmista-viesti-kentät + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Anna CasinoCoin-osoite (esim. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Klikkaa "Allekirjoita Viesti luodaksesi allekirjoituksen + + + + Enter CasinoCoin signature + Syötä CasinoCoin-allekirjoitus + + + + + The entered address is invalid. + Syötetty osoite on virheellinen. + + + + + + + Please check the address and try again. + Tarkista osoite ja yritä uudelleen. + + + + + The entered address does not refer to a key. + Syötetyn osoitteen avainta ei löydy. + + + + Wallet unlock was cancelled. + Lompakon avaaminen peruttiin. + + + + Private key for the entered address is not available. + Yksityistä avainta syötetylle osoitteelle ei ole saatavilla. + + + + Message signing failed. + Viestin allekirjoitus epäonnistui. + + + + Message signed. + Viesti allekirjoitettu. + + + + The signature could not be decoded. + Allekirjoitusta ei pystytty tulkitsemaan. + + + + + Please check the signature and try again. + Tarkista allekirjoitus ja yritä uudelleen. + + + + The signature did not match the message digest. + Allekirjoitus ei täsmää viestin tiivisteeseen. + + + + Message verification failed. + Viestin varmistus epäonnistui. + + + + Message verified. + Viesti varmistettu. + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Avoinna %1 lohkolle - - - + Open until %1 Avoinna %1 asti - - %1/offline? - %1/ei linjalla? + + %1/offline + %1/offline - + %1/unconfirmed %1/vahvistamaton - + %1 confirmations %1 vahvistusta - - <b>Status:</b> - <b>Tila:</b> + + Status + Tila + + + + , broadcast through %n node(s) + lähetetty %n noodin läpilähetetty %n noodin läpi - + + Date + Päivämäärä + + + + Source + Lähde + + + + Generated + Generoitu + + + + + From + Lähettäjä + + + + + + To + Saaja + + + + + own address + oma osoite + + + + label + nimi + + + + + + + + Credit + Credit + + + + matures in %n more block(s) + kypsyy %n lohkon kuluttuakypsyy %n lohkon kuluttua + + + + not accepted + ei hyväksytty + + + + + + + Debit + Debit + + + + Transaction fee + Maksukulu + + + + Net amount + Netto määrä + + + + Message + Viesti + + + + Comment + Viesti + + + + Transaction ID + Siirtotunnus + + + + Generated coins must mature 120 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. + Generoitujen kolikoiden täytyy kypsyä 120 lohkon ajan ennen kuin ne voidaan lähettää. Kun loit tämän lohkon, se lähetettiin verkkoon lisättäväksi lohkoketjuun. Jos se ei päädy osaksi lohkoketjua, sen tila vaihtuu "ei hyväksytty" ja sitä ei voida lähettää. Näin voi joskus käydä, jos toinen noodi löytää lohkon muutamaa sekuntia ennen tai jälkeen sinun lohkosi löytymisen. + + + + Debug information + Debug tiedot + + + + Transaction + Rahansiirto + + + + Inputs + Sisääntulot + + + + Amount + Määrä + + + + true + tosi + + + + false + epätosi + + + , has not been successfully broadcast yet , ei ole vielä onnistuneesti lähetetty - - - , broadcast through %1 node - , lähetetään %1 solmun kautta + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , lähetetään %1 solmun kautta - - - - <b>Date:</b> - <b>Päivä:</b> - - - - <b>Source:</b> Generated<br> - <b>Lähde:</b> Generoitu<br> - - - - - <b>From:</b> - <b>Lähettäjä:</b> - - - + unknown tuntematon - - - - - <b>To:</b> - <b>Vast. ott.:</b> - - - - (yours, label: - (sinun, tunniste: - - - - (yours) - (sinun) - - - - - - - <b>Credit:</b> - <b>Krediitti:</b> - - - - (%1 matures in %2 more blocks) - (%1 erääntyy %2 useammassa lohkossa) - - - - (not accepted) - (ei hyväksytty) - - - - - - <b>Debit:</b> - <b>Debit:</b> - - - - <b>Transaction fee:</b> - <b>Rahansiirtomaksu:</b> - - - - <b>Net amount:</b> - <b>Nettomäärä:</b> - - - - Message: - Viesti: - - - - Comment: - Kommentti: - - - - Transaction ID: - Rahansiirron ID: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Luotujen kolikoiden on odotettava 120 lohkoa ennen kuin ne voidaan käyttää. Kun loit tämän lohkon, se lähetettiin verkkoon lisättäväksi lohkoketjuun. Jos se epäonnistuu ketjuun liittymisessä, sen tila muuttuu "ei hyväksytty" eikä sitä voi käyttää. Tätä voi silloin tällöin esiintyä jos toinen solmu luo lohkon muutamia sekunteja omastasi. - TransactionDescDialog - + Transaction details Rahansiirron yksityiskohdat - + This pane shows a detailed description of the transaction Tämä ruutu näyttää yksityiskohtaisen tiedon rahansiirrosta @@ -1575,117 +1848,117 @@ Osoite: %4 TransactionTableModel - + Date Päivämäärä - + Type Laatu - + Address Osoite - + Amount Määrä - - Open for %n block(s) - Auki %n lohkolleAuki %n lohkoille + + Open for %n more block(s) + - + Open until %1 Avoinna %1 asti - + Offline (%1 confirmations) Ei yhteyttä verkkoon (%1 vahvistusta) - + Unconfirmed (%1 of %2 confirmations) Vahvistamatta (%1/%2 vahvistusta) - + Confirmed (%1 confirmations) Vahvistettu (%1 vahvistusta) - - Mined balance will be available in %n more blocks - Louhittu saldo tulee saataville %n lohkossaLouhittu saldo tulee saataville %n lohkossa + + Mined balance will be available when it matures in %n more block(s) + Louhittu saldo on käytettävissä kun se kypsyy %n lohkon päästäLouhittu saldo on käytettävissä kun se kypsyy %n lohkon päästä - + This block was not received by any other nodes and will probably not be accepted! Tätä lohkoa ei vastaanotettu mistään muusta solmusta ja sitä ei mahdollisesti hyväksytä! - + Generated but not accepted Generoitu mutta ei hyväksytty - + Received with Vastaanotettu osoitteella - + Received from Vastaanotettu - + Sent to Saaja - + Payment to yourself Maksu itsellesi - + Mined Louhittu - + (n/a) (ei saatavilla) - + Transaction status. Hover over this field to show number of confirmations. Rahansiirron tila. Siirrä osoitin kentän päälle nähdäksesi vahvistusten lukumäärä. - + Date and time that the transaction was received. Rahansiirron vastaanottamisen päivämäärä ja aika. - + Type of transaction. Rahansiirron laatu. - + Destination address of transaction. - Rahansiirron kohteen Bitcoin-osoite + Rahansiirron kohteen CasinoCoin-osoite - + Amount removed from or added to balance. Saldoon lisätty tai siitä vähennetty määrä. @@ -1693,817 +1966,958 @@ Osoite: %4 TransactionView - - + + All Kaikki - + Today Tänään - + This week Tällä viikolla - + This month Tässä kuussa - + Last month Viime kuussa - + This year Tänä vuonna - + Range... Alue... - + Received with Vastaanotettu osoitteella - + Sent to Saaja - + To yourself Itsellesi - + Mined Louhittu - + Other Muu - + Enter address or label to search Anna etsittävä osoite tai tunniste - + Min amount Minimimäärä - + Copy address Kopioi osoite - + Copy label Kopioi nimi - + Copy amount Kopioi määrä - + + Copy transaction ID + + + + Edit label Muokkaa nimeä - + Show transaction details - + Näytä rahansiirron yksityiskohdat - + Export Transaction Data Vie rahansiirron tiedot - + Comma separated file (*.csv) Comma separated file (*.csv) - + Confirmed Vahvistettu - + Date Aika - + Type Laatu - + Label Nimi - + Address Osoite - + Amount Määrä - + ID ID - + Error exporting Virhe tietojen viennissä - + Could not write to file %1. Ei voida kirjoittaa tiedostoon %1. - + Range: Alue: - + to kenelle - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopioi valittu osoite leikepöydälle - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Lähetetään... + + Send Coins + Lähetä CasinoCoineja - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Pienennä ilmaisinalueelle työkalurivin sijasta + + Export the data in the current tab to a file + Vie auki olevan välilehden tiedot tiedostoon - - Show only a tray icon after minimizing the window - Näytä ainoastaan pikkukuvake ikkunan pienentämisen jälkeen - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Ikkunaa suljettaessa vain pienentää Bitcoin-ohjelman ikkunan lopettamatta itse ohjelmaa. Kun tämä asetus on valittuna, ohjelman voi sulkea vain valitsemalla Lopeta ohjelman valikosta. + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + Varmuuskopio Onnistui + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - Bitcoinin versio + + CasinoCoin version + CasinoCoinin versio - + Usage: Käyttö: - - Send command to -server or bitcoind - Lähetä käsky palvelimelle tai bitcoind:lle + + Send command to -server or casinocoind + Lähetä käsky palvelimelle tai casinocoind:lle - + List commands Lista komennoista - + Get help for a command Hanki apua käskyyn - + Options: Asetukset: - - Specify configuration file (default: bitcoin.conf) - Määritä asetustiedosto (oletus: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Määritä asetustiedosto (oletus: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Määritä pid-tiedosto (oletus: bitcoin.pid) + + Specify pid file (default: casinocoind.pid) + Määritä pid-tiedosto (oletus: casinocoin.pid) - - Generate coins - Generoi kolikoita - - - - Don't generate coins - Älä generoi kolikoita - - - + Specify data directory Määritä data-hakemisto - + Set database cache size in megabytes (default: 25) Aseta tietokannan välimuistin koko megatavuina (oletus: 25) - - Set database disk log size in megabytes (default: 100) - Aseta tietokannan lokitiedoston koko megatavuina (oletus: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Kuuntele yhteyksiä portista <port> (oletus: 47950 tai testnet: 17950) - - Specify connection timeout (in milliseconds) - Määritä yhteyden aikakatkaisu (millisekunneissa) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Kuuntele yhteyksiä portista <port> (oletus: 8333 tai testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Pidä enintään <n> yhteyttä verkkoihin (oletus: 125) - - Connect only to the specified node - Muodosta yhteys vain tiettyyn solmuun - - - + Connect to a node to retrieve peer addresses, and disconnect - + Yhdistä noodiin hakeaksesi naapurien osoitteet ja katkaise yhteys - + Specify your own public address - + Määritä julkinen osoitteesi - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Kynnysarvo aikakatkaisulle heikosti toimiville verkoille (oletus: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Sekuntien määrä, kuinka kauan uudelleenkytkeydytään verkkoihin (oletus: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maksimi verkkoyhteyden vastaanottopuskuri, <n>*1000 tavua (oletus: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Virhe valmisteltaessa RPC-portin %u avaamista kuunneltavaksi: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maksimi verkkoyhteyden lähetyspuskuri, <n>*1000 tavua (oletus: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Kuuntele JSON-RPC -yhteyksiä portista <port> (oletus: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Hyväksy merkkipohjaiset- ja JSON-RPC-käskyt - + Run in the background as a daemon and accept commands Aja taustalla daemonina ja hyväksy komennot - + Use the test network Käytä test -verkkoa - - Output extra debugging information - Tulosta ylimääräistä debuggaustietoa + + Accept connections from outside (default: 1 if no -proxy or -connect) + Hyväksy yhteyksiä ulkopuolelta (vakioasetus: 1 jos -proxy tai -connect ei määritelty) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Virhe ilmennyt asetettaessa RPC-porttia %u IPv6:n kuuntelemiseksi, palataan takaisin IPv4:ään %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Aseta suurin korkean prioriteetin / matalan palkkion siirron koko tavuissa (vakioasetus: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Varoitus: -paytxfee on asetettu erittäin korkeaksi! Tämä on maksukulu jonka tulet maksamaan kun lähetät siirron. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Varoitus: Näytetyt siirrot eivät välttämättä pidä paikkaansa! Sinun tai toisten noodien voi olla tarpeen asentaa päivitys. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Varoitus: Tarkista että tietokoneesi kellonaika ja päivämäärä ovat paikkansapitäviä! CasinoCoin ei toimi oikein väärällä päivämäärällä ja/tai kellonajalla. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + Lohkon luonnin asetukset: + + + + Connect only to the specified node(s) + Yhidstä ainoastaan määrättyihin noodeihin + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + Hae oma IP osoite (vakioasetus: 1 kun kuuntelemassa ja ei -externalip) + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + Virhe avattaessa lohkoindeksiä + + + + Error: Disk space is low! + Varoitus: Levytila on vähissä! + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + Virhe: Järjestelmävirhe + + + + Failed to listen on any port. Use -listen=0 if you want this. + Ei onnistuttu kuuntelemaan missään portissa. Käytä -listen=0 jos haluat tätä. + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + Lohkon kirjoitus epäonnistui + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + Hae naapureita DNS hauilla (vakioasetus: 1 paitsi jos -connect) + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + Tuodaan lohkoja ulkoisesta blk000??.dat tiedostosta + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Tietoa + + + + Invalid -tor address: '%s' + Virheellinen -tor osoite '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Suurin vastaanottopuskuri yksittäiselle yhteydelle, <n>*1000 tavua (vakioasetus: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Suurin lähetyspuskuri yksittäiselle yhteydelle, <n>*1000 tavua (vakioasetus: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Yhdistä vain noodeihin verkossa <net> (IPv4, IPv6 tai Tor) + + + + Output extra debugging information. Implies all other -debug* options + Tulosta enemmän debug tietoa. Aktivoi kaikki -debug* asetukset + + + + Output extra network debugging information + Tulosta lisää verkkoyhteys debug tietoa + + + Prepend debug output with timestamp Lisää debuggaustiedon tulostukseen aikaleima - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL asetukset (katso CasinoCoin Wikistä tarkemmat SSL ohjeet) + + + + Select the version of socks proxy to use (4-5, default: 5) + Valitse käytettävän SOCKS-proxyn versio (4-5, vakioasetus: 5) + + + Send trace/debug info to console instead of debug.log file Lähetä jäljitys/debug-tieto konsoliin, debug.log-tiedoston sijaan - + Send trace/debug info to debugger Lähetä jäljitys/debug-tieto debuggeriin - + + Set maximum block size in bytes (default: 250000) + Aseta suurin lohkon koko tavuissa (vakioasetus: 250000) + + + + Set minimum block size in bytes (default: 0) + Asetan pienin lohkon koko tavuissa (vakioasetus: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Pienennä debug.log tiedosto käynnistyksen yhteydessä (vakioasetus: 1 kun ei -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Määritä yhteyden aikakataisu millisekunneissa (vakioasetus: 5000) + + + + System error: + Järjestelmävirhe: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Käytä UPnP:tä kuunneltavan portin avaamiseen (vakioasetus: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Käytä UPnP:tä kuunneltavan portin avaamiseen (vakioasetus: 1 kun kuuntelemassa) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Käytä proxyä tor yhteyksien avaamiseen (vakioasetus: sama kuin -proxy) + + + Username for JSON-RPC connections Käyttäjätunnus JSON-RPC-yhteyksille - + + Warning + Varoitus + + + + Warning: This version is obsolete, upgrade required! + Varoitus: Tämä versio on vanhentunut, päivitys tarpeen! + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + Password for JSON-RPC connections Salasana JSON-RPC-yhteyksille - - Listen for JSON-RPC connections on <port> (default: 8332) - Kuuntele JSON-RPC -yhteyksiä portista <port> (oletus: 8332) - - - + Allow JSON-RPC connections from specified IP address Salli JSON-RPC yhteydet tietystä ip-osoitteesta - + Send commands to node running on <ip> (default: 127.0.0.1) Lähetä käskyjä solmuun osoitteessa <ip> (oletus: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Suorita käsky kun paras lohko muuttuu (%s cmd on vaihdettu block hashin kanssa) - + Upgrade wallet to latest format Päivitä lompakko uusimpaan formaattiin - + Set key pool size to <n> (default: 100) Aseta avainpoolin koko arvoon <n> (oletus: 100) - + Rescan the block chain for missing wallet transactions Skannaa uudelleen lohkoketju lompakon puuttuvien rahasiirtojen vuoksi - - How many blocks to check at startup (default: 2500, 0 = all) - Kuinka monta lohkoa tarkistetaan käynnistettäessä (oletus: 2500, 0 = kaikki) - - - - How thorough the block verification is (0-6, default: 1) - Kuinka tiukka lohkovarmistus on (0-6, oletus: 1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - SSL-asetukset: (lisätietoja Bitcoin-Wikistä) - - - + Use OpenSSL (https) for JSON-RPC connections Käytä OpenSSL:ää (https) JSON-RPC-yhteyksille - + Server certificate file (default: server.cert) Palvelimen sertifikaatti-tiedosto (oletus: server.cert) - + Server private key (default: server.pem) Palvelimen yksityisavain (oletus: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Hyväksyttävä salaus (oletus: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Tämä ohjeviesti - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - En pääse käsiksi data-hakemiston lukitukseen %s. Bitcoin on todennäköisesti jo käynnistetty. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Kytkeytyminen %s tällä tietokonella ei onnistu (kytkeytyminen palautti virheen %d, %s) - + Connect through socks proxy - + Yhdistä socks proxyn läpi - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Salli DNS kyselyt -addnode, -seednode ja -connect yhteydessä - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Ladataan osoitteita... - - Error loading blkindex.dat - Virhe ladattaessa blkindex.dat-tiedostoa - - - + Error loading wallet.dat: Wallet corrupted Virhe ladattaessa wallet.dat-tiedostoa: Lompakko vioittunut - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Virhe ladattaessa wallet.dat-tiedostoa: Tarvitset uudemman version Bitcoinista + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Virhe ladattaessa wallet.dat-tiedostoa: Tarvitset uudemman version CasinoCoinista - - Wallet needed to be rewritten: restart Bitcoin to complete - Lompakko tarvitsee uudelleenkirjoittaa: käynnistä Bitcoin uudelleen + + Wallet needed to be rewritten: restart CasinoCoin to complete + Lompakko tarvitsee uudelleenkirjoittaa: käynnistä CasinoCoin uudelleen - + Error loading wallet.dat Virhe ladattaessa wallet.dat-tiedostoa - + Invalid -proxy address: '%s' - + Virheellinen proxy-osoite '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Tuntematon verkko -onlynet parametrina: '%s' - + Unknown -socks proxy version requested: %i - + Tuntematon -socks proxy versio pyydetty: %i - + Cannot resolve -bind address: '%s' - + -bind osoitteen '%s' selvittäminen epäonnistui - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + -externalip osoitteen '%s' selvittäminen epäonnistui - + Invalid amount for -paytxfee=<amount>: '%s' - + -paytxfee=<amount>: '%s' on virheellinen - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Virhe: Lompakko on lukittu, rahansiirtoa ei voida luoda - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Virhe: Tämä rahansiirto vaatii rahansiirtopalkkion vähintään %s johtuen sen määrästä, monimutkaisuudesta tai hiljattain vastaanotettujen summien käytöstä - - - - Error: Transaction creation failed - Virhe: Rahansiirron luonti epäonnistui - - - - Sending... - Lähetetään... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Virhe: Rahansiirto hylättiin. Tämä voi tapahtua jos jotkin bitcoineistasi on jo käytetty, esimerkiksi jos olet käyttänyt kopiota wallet.dat-lompakkotiedostosta ja bitcoinit on merkitty käytetyksi vain kopiossa. - - - + Invalid amount Virheellinen määrä - + Insufficient funds Lompakon saldo ei riitä - + Loading block index... Ladataan lohkoindeksiä... - + Add a node to connect to and attempt to keep the connection open Linää solmu mihin liittyä pitääksesi yhteyden auki - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Kytkeytyminen %s ei onnistu tällä tietokoneella. CasinoCoin on todennäköisesti jo ajamassa. - - Find peers using internet relay chat (default: 0) - Etsi solmuja käyttäen internet relay chatia (oletus: 0) - - - - Accept connections from outside (default: 1) - Hyväksytään ulkopuoliset yhteydet (oletus: 1) - - - - Find peers using DNS lookup (default: 1) - Etsi solmuja käyttämällä DNS hakua (oletus: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Käytä Plug and Play kartoitusta kuunnellaksesi porttia (oletus: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Käytä Plug and Play kartoitusta kuunnellaksesi porttia (oletus: 0) - - - + Fee per KB to add to transactions you send Rahansiirtopalkkio per KB lisätään lähettämääsi rahansiirtoon - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Ladataan lompakkoa... - + Cannot downgrade wallet Et voi päivittää lompakkoasi vanhempaan versioon - - Cannot initialize keypool - Avainvarastoa ei voi alustaa - - - + Cannot write default address Oletusosoitetta ei voi kirjoittaa - + Rescanning... Skannataan uudelleen... - + Done loading Lataus on valmis - + To use the %s option Käytä %s optiota - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, sinun täytyy asettaa rpcpassword asetustiedostoon: -%s -On suositeltavaa käyttää seuraavaan satunnaista salasanaa: -rpcuser=bitcoinrpc -rpcpassword=%s -(sinun ei tarvitse muistaa tätä salasanaa) -Jos tiedostoa ei ole, niin luo se ainoastaan omistajan kirjoitusoikeuksin. - - - - + Error Virhe - - An error occured while setting up the RPC port %i for listening: %s - Virhe asetettaessa RCP-porttia %i kuunteluun: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2511,10 +2925,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Jos tiedostoa ei ole, niin luo se ainoastaan omistajan kirjoitusoikeuksin. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Varoitus: Tarkista, ovatko tietokoneesi päivämäärä ja aika oikein. Mikäli aika on väärin, Bitcoin-ohjelma ei toimi oikein. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 03ff69e..dbffa30 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -3,140 +3,178 @@ AboutDialog - - About Bitcoin - À propos de Bitcoin + + About CasinoCoin + À propos de CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> version + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> version - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Développeurs de Bitcoin + + Ce logiciel est en phase expérimentale. -Ce logiciel est en phase expérimentale. + Distribué sous licence MIT/X11, voir le fichier COPYING ou http://www.opensource.org/licenses/mit-license.php. -Distribué sous licence MIT/X11, voir le fichier license.txt ou http://www.opensource.org/licenses/mit-license.php. - -Ce produit comprend des logiciels développés par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL (http://www.openssl.org/), un logiciel cryptographique écrit par Eric Young (eay@cryptsoft.com) et un logiciel UPnP écrit par Thomas Bernard. + Ce produit comprend des fonctionnalités développées par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL (http://www.openssl.org/), un logiciel cryptographique écrit par Eric Young (eay@cryptsoft.com), et des fonctionnalités développées pour le logiciel UPnP écrit par Thomas Bernard. + + + + Copyright + Droit d'auteur + + + + The CasinoCoin developers + Les développeurs CasinoCoin AddressBookPage - + Address Book - Options interface utilisateur + Carnet d'adresses - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Voici vos adresses Bitcoin qui vous permettent de recevoir des paiements. Vous pouvez donner une adresse différente à chaque expéditeur afin de savoir qui vous paye. - - - + Double-click to edit address or label Double cliquez afin de modifier l'adresse ou l'étiquette - + Create a new address Créer une nouvelle adresse - + Copy the currently selected address to the system clipboard - Signature invalide + Copier l'adresse sélectionnée dans le presse-papiers - + &New Address &Nouvelle adresse - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Voici vos adresses CasinoCoin qui vous permettent de recevoir des paiements. Vous pouvez donner une adresse différente à chaque expéditeur afin de savoir qui vous paye. + + + &Copy Address &Copier l'adresse - + Show &QR Code Afficher le &QR Code - - Sign a message to prove you own this address - Signer un message pour prouver que vous détenez cette adresse + + Sign a message to prove you own a CasinoCoin address + Signer un message pour prouver que vous détenez une adresse CasinoCoin - - &Sign Message - &Signer un message + + Sign &Message + Signer un &message - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Supprimer l'adresse sélectionnée dans la liste. Seules les adresses d'envoi peuvent être supprimées. + + Delete the currently selected address from the list + Effacer l'adresse actuellement sélectionnée de la liste - + + Export the data in the current tab to a file + Exporter les données de l'onglet courant vers un fichier + + + + &Export + &Exporter + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Vérifier un message pour vous assurer qu'il a bien été signé avec l'adresse CasinoCoin spécifiée + + + + &Verify Message + &Vérifier un message + + + &Delete &Supprimer - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Ce sont vos adresses CasinoCoin pour émettre des paiements. Vérifiez toujours le montant et l'adresse du destinataire avant d'envoyer des pièces. + + + Copy &Label Copier l'é&tiquette - + &Edit &Éditer - + + Send &Coins + Envoyer des Bit&coins + + + Export Address Book Data Exporter les données du carnet d'adresses - + Comma separated file (*.csv) Valeurs séparées par des virgules (*.csv) - + Error exporting Erreur lors de l'exportation - + Could not write to file %1. - Impossible d'écrire sur le fichier %1. + Impossible d'écrire dans le fichier %1. AddressTableModel - + Label Étiquette - + Address Adresse - + (no label) (aucune étiquette) @@ -144,976 +182,951 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être AskPassphraseDialog - + Passphrase Dialog Dialogue de phrase de passe - + Enter passphrase Entrez la phrase de passe - + New passphrase Nouvelle phrase de passe - + Repeat new passphrase Répétez la phrase de passe - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - Entrez une nouvelle phrase de passe pour le porte-monnaie.<br/>Veuillez utiliser une phrase de <b>10 caractères au hasard ou plus</b> ou bien de <b>huit mots ou plus</b>. + Entrez une nouvelle phrase de passe pour le porte-monnaie.<br/>Veuillez utiliser une phrase composée de <b>10 caractères aléatoires ou plus</b>, ou bien de <b>huit mots ou plus</b>. - + Encrypt wallet Chiffrer le porte-monnaie - + This operation needs your wallet passphrase to unlock the wallet. Cette opération nécessite votre phrase de passe pour déverrouiller le porte-monnaie. - + Unlock wallet Déverrouiller le porte-monnaie - + This operation needs your wallet passphrase to decrypt the wallet. Cette opération nécessite votre phrase de passe pour décrypter le porte-monnaie. - + Decrypt wallet - Décrypter le porte-monnaie + Déchiffrer le porte-monnaie - + Change passphrase Changer la phrase de passe - + Enter the old and new passphrase to the wallet. Entrez l’ancienne phrase de passe pour le porte-monnaie ainsi que la nouvelle. - + Confirm wallet encryption Confirmer le chiffrement du porte-monnaie - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ATTENTION : Si vous chiffrez votre porte-monnaie et perdez votre phrase de passe, vous <b>PERDREZ TOUS VOS BITCOINS</b> ! -Êtes-vous sûr de vouloir chiffrer votre porte-monnaie ? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Attention : Si vous chiffrez votre porte-monnaie et perdez votre phrase de passe, vous <b>PERDREZ ACCÈS À TOUS VOS CASINOCOINS</b> ! - - + + Are you sure you wish to encrypt your wallet? + Êtes-vous sûr de vouloir chiffrer votre porte-monnaie ? + + + + 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. + IMPORTANT : Les sauvegardes précédentes de votre fichier de porte-monnaie devraient être remplacées par le nouveau fichier crypté de porte-monnaie. Pour des raisons de sécurité, les précédentes sauvegardes de votre fichier de porte-monnaie non chiffré deviendront inutilisables dès que vous commencerez à utiliser le nouveau porte-monnaie chiffré. + + + + + Warning: The Caps Lock key is on! + Attention : la touche Verr. Maj. est activée ! + + + + Wallet encrypted Porte-monnaie chiffré - - Bitcoin 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. - Bitcoin va à présent se fermer pour terminer la procédure de cryptage. N'oubliez pas que le chiffrement de votre porte-monnaie ne peut pas fournir une protection totale contre le vol par des logiciels malveillants qui infecteraient votre ordinateur. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin va à présent se fermer pour terminer la procédure de cryptage. N'oubliez pas que le chiffrement de votre porte-monnaie ne peut pas fournir une protection totale contre le vol par des logiciels malveillants qui infecteraient votre ordinateur. - - - Warning: The Caps Lock key is on. - Attention : la touche Verrouiller Maj est activée. - - - - - - + + + + Wallet encryption failed Le chiffrement du porte-monnaie a échoué - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Le chiffrement du porte-monnaie a échoué en raison d'une erreur interne. Votre porte-monnaie n'a pas été chiffré. - - + + The supplied passphrases do not match. Les phrases de passe entrées ne correspondent pas. - + Wallet unlock failed Le déverrouillage du porte-monnaie a échoué - - - + + + The passphrase entered for the wallet decryption was incorrect. La phrase de passe entrée pour décrypter le porte-monnaie était incorrecte. - + Wallet decryption failed - Le décryptage du porte-monnaie a échoué + Le déchiffrage du porte-monnaie a échoué - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. La phrase de passe du porte-monnaie a été modifiée avec succès. BitcoinGUI - - Bitcoin Wallet - Porte-monnaie Bitcoin - - - + Sign &message... - Signer le &message... + Signer un &message... - - Show/Hide &Bitcoin - Afficher/Cacher &Bitcoin - - - + Synchronizing with network... - Synchronisation avec le réseau... + Synchronisation avec le réseau… - + &Overview &Vue d'ensemble - + Show general overview of wallet - Affiche une vue d'ensemble du porte-monnaie + Afficher une vue d’ensemble du porte-monnaie - + &Transactions &Transactions - + Browse transaction history - Permet de parcourir l'historique des transactions + Parcourir l'historique des transactions - - &Address Book - Carnet d'&adresses - - - + Edit the list of stored addresses and labels Éditer la liste des adresses et des étiquettes stockées - - &Receive coins - &Recevoir des pièces - - - + Show the list of addresses for receiving payments - Affiche la liste des adresses pour recevoir des paiements + Afficher la liste des adresses pour recevoir des paiements - - &Send coins - &Envoyer des pièces - - - - Prove you control an address - Prouver que vous contrôlez une adresse - - - + E&xit Q&uitter - + Quit application - Quitter l'application + Quitter l’application - - &About %1 - &À propos de %1 + + Show information about CasinoCoin + Afficher des informations à propos de CasinoCoin - - Show information about Bitcoin - Afficher des informations à propos de Bitcoin - - - + About &Qt À propos de &Qt - + Show information about Qt Afficher des informations sur Qt - + &Options... - &Options... + &Options… - + &Encrypt Wallet... &Chiffrer le porte-monnaie... - + &Backup Wallet... &Sauvegarder le porte-monnaie... - + &Change Passphrase... &Modifier la phrase de passe... - - - ~%n block(s) remaining - ~%n bloc restant~%n blocs restants + + + Importing blocks from disk... + Importation des blocs depuis le disque... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - %1 blocs de l'historique des transactions sur %2 téléchargés (%3% effectué). + + Reindexing blocks on disk... + Réindexation des blocs sur le disque... - - &Export... - &Exporter... + + Send coins to a CasinoCoin address + Envoyer des pièces à une adresse CasinoCoin - - Send coins to a Bitcoin address - Envoyer des pièces à une adresse Bitcoin + + Modify configuration options for CasinoCoin + Modifier les options de configuration de CasinoCoin - - Modify configuration options for Bitcoin - Modifier les options de configuration de Bitcoin - - - - Show or hide the Bitcoin window - Afficher ou cacher la fenêtre Bitcoin - - - - Export the data in the current tab to a file - Exporter les données de l'onglet courant vers un fichier - - - - Encrypt or decrypt wallet - Chiffrer ou décrypter le porte-monnaie - - - + Backup wallet to another location Sauvegarder le porte-monnaie à un autre emplacement - + Change the passphrase used for wallet encryption - Modifier la phrase de passe utilisée pour le cryptage du porte-monnaie + Modifier la phrase de passe utilisée pour le chiffrement du porte-monnaie - + &Debug window Fenêtre de &débogage - + Open debugging and diagnostic console Ouvrir une console de débogage et de diagnostic - + &Verify message... - &Vérifier le message... + &Vérifier un message... - - Verify a message signature - Vérifier la signature d'un message + + + CasinoCoin + CasinoCoin - + + Wallet + Porte-monnaie + + + + &Send + &Envoyer + + + + &Receive + &Recevoir + + + + &Addresses + &Adresses + + + + &About CasinoCoin + À &propos de CasinoCoin + + + + &Show / Hide + &Afficher / Cacher + + + + Show or hide the main Window + Afficher ou masquer la fenêtre principale + + + + Encrypt the private keys that belong to your wallet + Crypter les clefs privées de votre porte-monnaie + + + + Sign messages with your CasinoCoin addresses to prove you own them + Signer les messages avec vos adresses CasinoCoin pour prouver que vous les détenez + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Vérifier les messages pour vous assurer qu'ils ont bien été signés avec les adresses CasinoCoin spécifiées + + + &File &Fichier - + &Settings &Réglages - + &Help &Aide - + Tabs toolbar Barre d'outils des onglets - - Actions toolbar - Barre d'outils des actions - - - - + + [testnet] [testnet] - - - Bitcoin client - Client Bitcoin + + CasinoCoin client + Client CasinoCoin - - %n active connection(s) to Bitcoin network - %n connexion active avec le réseau Bitcoin%n connexions actives avec le réseau Bitcoin + + %n active connection(s) to CasinoCoin network + %n connexion active avec le réseau CasinoCoin%n connexions actives avec le réseau CasinoCoin - - Downloaded %1 blocks of transaction history. - %1 blocs de l'historique des transactions téléchargés. - - - - %n second(s) ago - il y a %n secondeil y a %n secondes - - - - %n minute(s) ago - il y a %n minuteil y a %n minutes - - - - %n hour(s) ago - il y a %n heureil y a %n heures - - - - %n day(s) ago - il y a %n jouril y a %n jours + + No block source available... + Aucune source de bloc disponible... - + + Processed %1 of %2 (estimated) blocks of transaction history. + %1 blocs sur %2 (estimés) de l'historique des transactions traités. + + + + Processed %1 blocks of transaction history. + %1 blocs de l'historique des transactions traités. + + + + %n hour(s) + %n heure%n heures + + + + %n day(s) + %n jour%n jours + + + + %n week(s) + %n semaine%n semaines + + + + %1 behind + %1 en arrière + + + + Last received block was generated %1 ago. + Le dernier bloc reçu avait été généré il y a %1. + + + + Transactions after this will not yet be visible. + Les transactions après cela ne seront pas encore visibles. + + + + Error + Erreur + + + + Warning + Avertissement + + + + Information + Information + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Cette transaction dépasse la limite de taille. Vous pouvez quand même l'envoyer en vous acquittant de frais d'un montant de %1 qui iront aux nœuds qui traiteront la transaction et aideront à soutenir le réseau. Voulez-vous payer les frais ? + + + Up to date À jour - + Catching up... - Rattrapage... + Rattrapage… - - Last received block was generated %1. - Le dernier bloc reçu a été généré %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Cette transaction dépasse la limite de taille. Vous pouvez quand même l'envoyer en vous acquittant de frais d'un montant de %1, qui iront aux nœuds qui traiteront la transaction et aideront à soutenir le réseau. Voulez-vous payer les frais ? - - - + Confirm transaction fee Confirmer les frais de transaction - + Sent transaction Transaction envoyée - + Incoming transaction Transaction entrante - + Date: %1 Amount: %2 Type: %3 Address: %4 - Date : %1 -Montant : %2 -Type : %3 -Adresse : %4 + Date : %1 +Montant : %2 +Type : %3 +Adresse : %4 - + + + URI handling + Gestion des URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + L'URI ne peut être analysé ! Cela peut être causé par une adresse CasinoCoin invalide ou par des paramètres d'URI malformés. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Le porte-monnaie est <b>chiffré</b> et est actuellement <b>déverrouillé</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Le porte-monnaie est <b>chiffré</b> et est actuellement <b>verrouillé</b> - - Backup Wallet - Sauvegarder le porte-monnaie - - - - Wallet Data (*.dat) - Données de porte-monnaie (*.dat) - - - - Backup Failed - La sauvegarde a échoué - - - - There was an error trying to save the wallet data to the new location. - Une erreur est survenue lors de l'enregistrement des données de porte-monnaie à un autre emplacement. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Une erreur fatale est survenue. Bitcoin ne peut plus continuer à fonctionner de façon sûre et va s'arrêter. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Une erreur fatale est survenue. CasinoCoin ne peut plus continuer à fonctionner de façon sûre et va s'arrêter. ClientModel - + Network Alert Alerte réseau - - DisplayOptionsPage - - - Display - Affichage - - - - default - par défaut - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - La langue de l'interface utilisateur peut être définie ici. Ce réglage ne sera pris en compte qu'après un redémarrage de Bitcoin. - - - - User Interface &Language: - &Langue de l'interface utilisateur : - - - - &Unit to show amounts in: - &Unité d'affichage des montants : - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Choisissez la sous-unité par défaut pour l'affichage dans l'interface et lors de l'envoi de pièces - - - - &Display addresses in transaction list - &Afficher les adresses sur la liste des transactions - - - - Whether to show Bitcoin addresses in the transaction list - Détermine si les adresses Bitcoin seront affichées sur la liste des transactions - - - - Warning - Attention - - - - This setting will take effect after restarting Bitcoin. - Ce réglage sera pris en compte après un redémarrage de Bitcoin. - - EditAddressDialog - + Edit Address Éditer l'adresse - + &Label &Étiquette - + The label associated with this address book entry - L'étiquette associée à cette entrée du carnet d'adresses + L’étiquette associée à cette entrée du carnet d'adresses - + &Address &Adresse - + The address associated with this address book entry. This can only be modified for sending addresses. - L'adresse associée avec cette entrée du carnet d'adresses. Ne peut être modifiée que pour les adresses d'envoi. + L’adresse associée avec cette entrée du carnet d'adresses. Ne peut être modifiées que les adresses d’envoi. - + New receiving address Nouvelle adresse de réception - + New sending address - Nouvelle adresse d'envoi + Nouvelle adresse d’envoi - + Edit receiving address - Éditer l'adresse de réception + Éditer l’adresse de réception - + Edit sending address - Éditer l'adresse d'envoi + Éditer l’adresse d'envoi - + The entered address "%1" is already in the address book. - L'adresse fournie « %1 » est déjà présente dans le carnet d'adresses. + L’adresse fournie « %1 » est déjà présente dans le carnet d'adresses. - - The entered address "%1" is not a valid Bitcoin address. - L'adresse fournie « %1 » n'est pas une adresse Bitcoin valide. + + The entered address "%1" is not a valid CasinoCoin address. + L'adresse fournie « %1 » n'est pas une adresse CasinoCoin valide. - + Could not unlock wallet. Impossible de déverrouiller le porte-monnaie. - + New key generation failed. Échec de la génération de la nouvelle clef. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version version - + Usage: - Utilisation : + Utilisation : - - options - options + + command-line options + options de ligne de commande - + UI options Options Interface Utilisateur - + Set language, for example "de_DE" (default: system locale) - Définir la langue, par exemple « de_DE » (par défaut : la langue du système) + Définir la langue, par exemple « de_DE » (par défaut : la langue du système) - + Start minimized Démarrer sous forme minimisée - + Show splash screen on startup (default: 1) - Afficher l'écran d'accueil au démarrage (par défaut : 1) - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Détacher les bases de données des blocs et des adresses lors de la fermeture. Cela permet de les déplacer dans un autre répertoire de données mais ralentit la fermeture. Le porte-monnaie est toujours détaché. - - - - Pay transaction &fee - Payer des &frais de transaction - - - - Main - Principal - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Frais de transaction optionnels par ko qui aident à garantir un traitement rapide des transactions. La plupart des transactions occupent 1 ko. Des frais de 0.01 sont recommandés. - - - - &Start Bitcoin on system login - &Démarrer Bitcoin lors de l'ouverture d'une session - - - - Automatically start Bitcoin after logging in to the system - Démarrer Bitcoin automatiquement après avoir ouvert une session sur l'ordinateur - - - - &Detach databases at shutdown - &Détacher les bases de données lors de la fermeture - - - - MessagePage - - - Sign Message - Signer le message - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Vous pouvez signer des messages avec vos adresses pour prouver que les détenez. Faites attention à ne pas signer quoi que ce soit de vague car des attaques d'hameçonnage peuvent essayer d'obtenir votre identité par votre signature. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous serez d'accord. - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - L'adresse avec laquelle le message sera signé ( par ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Choisir une adresse depuis le carnet d'adresses - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Coller une adresse depuis le presse-papiers - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Entrez ici le message que vous désirez signer - - - - Copy the current signature to the system clipboard - Copier la signature actuelle dans le presse-papiers - - - - &Copy Signature - &Copier la signature - - - - Reset all sign message fields - Remettre à zéro tous les champs de signature de message - - - - Clear &All - &Tout nettoyer - - - - Click "Sign Message" to get signature - Cliquez sur « Signer le message » pour obtenir la signature - - - - Sign a message to prove you own this address - Signer le message pour prouver que vous détenez cette adresse - - - - &Sign Message - &Signer le message - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Entrez une adresse Bitcoin (par ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Une erreur est survenue lors de la signature - - - - %1 is not a valid address. - %1 n'est pas une adresse valide. - - - - %1 does not refer to a key. - %1 ne renvoie pas à une clef. - - - - Private key for %1 is not available. - La clef privée pour %1 n'est pas disponible. - - - - Sign failed - Échec de la signature - - - - NetworkOptionsPage - - - Network - Réseau - - - - Map port using &UPnP - Ouvrir le port avec l'&UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Ouvrir le port du client Bitcoin automatiquement sur le routeur. Cela ne fonctionne que si votre routeur supporte l'UPnP et si la fonctionnalité est activée. - - - - &Connect through SOCKS4 proxy: - &Connexion à travers un proxy SOCKS4 : - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Connexion au réseau Bitcoin à travers un proxy SOCKS4 (par ex. lors d'une connexion via Tor) - - - - Proxy &IP: - &IP du proxy : - - - - &Port: - &Port : - - - - IP address of the proxy (e.g. 127.0.0.1) - Adresse IP du proxy (par ex. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Port du proxy (par ex. 1234) + Afficher l'écran d'accueil au démarrage (par défaut : 1) OptionsDialog - + Options Options + + + &Main + Réglages &principaux + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Frais de transaction optionnel par ko qui aident à garantir un traitement rapide des transactions. La plupart des transactions utilisent 1 ko. + + + + Pay transaction &fee + Payer des &frais de transaction + + + + Automatically start CasinoCoin after logging in to the system. + Démarrer CasinoCoin automatiquement lors de l'ouverture une session sur l'ordinateur. + + + + &Start CasinoCoin on system login + &Démarrer CasinoCoin lors de l'ouverture d'une session + + + + Reset all client options to default. + Remettre toutes les options du client aux valeurs par défaut. + + + + &Reset Options + &Remise à zéro des options + + + + &Network + &Réseau + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Ouvrir le port du client CasinoCoin automatiquement sur le routeur. Cela ne fonctionne que si votre routeur supporte l'UPnP et si la fonctionnalité est activée. + + + + Map port using &UPnP + Ouvrir le port avec l'&UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Connexion au réseau CasinoCoin à travers un proxy SOCKS (par ex. lors d'une connexion via Tor). + + + + &Connect through SOCKS proxy: + &Connexion à travers un proxy SOCKS : + + + + Proxy &IP: + &IP du proxy : + + + + IP address of the proxy (e.g. 127.0.0.1) + Adresse IP du proxy (par ex. 127.0.0.1) + + + + &Port: + &Port : + + + + Port of the proxy (e.g. 9050) + Port du proxy (par ex. 9050) + + + + SOCKS &Version: + &Version SOCKS : + + + + SOCKS version of the proxy (e.g. 5) + Version SOCKS du serveur mandataire (par ex. 5) + + + + &Window + &Fenêtre + + + + Show only a tray icon after minimizing the window. + Afficher uniquement une icône système après minimisation. + + + + &Minimize to the tray instead of the taskbar + &Minimiser dans la barre système au lieu de la barre des tâches + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimiser au lieu quitter l'application lorsque la fenêtre est fermée. Lorsque cette option est activée, l'application ne pourra être fermée qu'en sélectionnant Quitter dans le menu déroulant. + + + + M&inimize on close + M&inimiser lors de la fermeture + + + + &Display + &Affichage + + + + User Interface &language: + &Langue de l'interface utilisateur : + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + La langue de l'interface utilisateur peut être définie ici. Ce réglage sera pris en compte après redémarrage de CasinoCoin. + + + + &Unit to show amounts in: + &Unité d'affichage des montants : + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Choisissez la sous-unité par défaut pour l'affichage dans l'interface et lors de l'envoi de pièces. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Détermine si les adresses CasinoCoin seront affichées sur la liste des transactions. + + + + &Display addresses in transaction list + &Afficher les adresses sur la liste des transactions + + + + &OK + &Valider + + + + &Cancel + A&nnuler + + + + &Apply + &Appliquer + + + + default + par défaut + + + + Confirm options reset + Confirmer la remise à zéro des options + + + + Some settings may require a client restart to take effect. + La prise en compte de certains réglages peut nécessiter un redémarrage du client. + + + + Do you want to proceed? + Voulez-vous continuer ? + + + + + Warning + Avertissement + + + + + This setting will take effect after restarting CasinoCoin. + Ce réglage sera pris en compte après un redémarrage de CasinoCoin. + + + + The supplied proxy address is invalid. + L'adresse de proxy fournie est invalide. + OverviewPage - + Form Formulaire - - - 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. - L'information affichée peut être obsolète. Votre porte-monnaie est automatiquement synchronisé avec le réseau Bitcoin lorsque la connexion s'établit, mais ce processus n'est pas encore terminé. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Les informations affichées peuvent être obsolètes. Votre porte-monnaie est automatiquement synchronisé avec le réseau CasinoCoin lorsque la connexion s'établit, or ce processus n'est pas encore terminé. - + Balance: - Solde : + Solde : - - Number of transactions: - Nombre de transactions : - - - + Unconfirmed: - Non confirmé : + Non confirmé : - + Wallet Porte-monnaie - + + Immature: + Immature : + + + + Mined balance that has not yet matured + Le solde généré n'est pas encore mûr + + + <b>Recent transactions</b> <b>Transactions récentes</b> - + Your current balance Votre solde actuel - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Total des transactions qui doivent encore être confirmées et qui ne sont pas prises en compte pour le solde actuel + Total des transactions qui doivent encore être confirmées et qui ne sont pas prises en compte dans le solde actuel - - Total number of transactions in wallet - Nombre total de transactions dans le porte-monnaie - - - - + + out of sync désynchronisé + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Impossible de démarrer casinocoin : gestionnaire de cliquer-pour-payer + + QRCodeDialog - + QR Code Dialog Dialogue de QR Code - - QR Code - QR Code - - - + Request Payment Demande de paiement - + Amount: - Montant : + Montant : - - BTC - BTC - - - + Label: - Étiquette : + Étiquette : - + Message: - Message : + Message : - + &Save As... &Enregistrer sous... - + Error encoding URI into QR Code. Erreur de l'encodage de l'URI dans le QR Code. - + + The entered amount is invalid, please check. + Le montant entré est invalide, veuillez le vérifier. + + + Resulting URI too long, try to reduce the text for label / message. L'URI résultant est trop long, essayez avec un texte d'étiquette ou de message plus court. - + Save QR Code Sauvegarder le QR Code - + PNG Images (*.png) Images PNG (*.png) @@ -1121,125 +1134,146 @@ Adresse : %4 RPCConsole - - Bitcoin debug window - Fenêtre de débogage de Bitcoin - - - + Client name Nom du client - - - - - - - - - + + + + + + + + + + N/A Indisponible - + Client version Version du client - + &Information - &Information + &Informations - - Client - Client + + Using OpenSSL version + Version d'OpenSSL utilisée - + Startup time - Temps de démarrage + Date de démarrage - + Network Réseau - + Number of connections Nombre de connexions - + On testnet Sur testnet - + Block chain Chaîne de blocs - + Current number of blocks Nombre actuel de blocs - + Estimated total blocks Nombre total estimé de blocs - + Last block time Horodatage du dernier bloc - - Debug logfile - Journal de débogage - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - Ouvrir le journal de débogage de Bitcoin depuis le répertoire courant. Cela peut prendre quelques secondes pour les journaux de grande taille. - - - + &Open &Ouvrir - + + Command-line options + Options de ligne de commande + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Afficher le message d'aide de CasinoCoin-Qt pour obtenir la liste des options de ligne de commande disponibles pour CasinoCoin. + + + + &Show + &Afficher + + + &Console &Console - + Build date Date de compilation - + + CasinoCoin - Debug window + CasinoCoin - Fenêtre de débogage + + + + CasinoCoin Core + Noyau CasinoCoin + + + + Debug log file + Journal de débogage + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Ouvrir le journal de débogage de CasinoCoin depuis le répertoire de données actuel. Cela peut prendre quelques secondes pour les journaux de grande taille. + + + Clear console Nettoyer la console - - Welcome to the Bitcoin RPC console. - Bienvenue sur la console RPC de Bitcoin. + + Welcome to the CasinoCoin RPC console. + Bienvenue sur la console RPC de CasinoCoin. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Utilisez les touches de curseur pour naviguer dans l'historique et <b>Ctrl-L</b> pour effacer l'écran. - + Type <b>help</b> for an overview of available commands. Tapez <b>help</b> pour afficher une vue générale des commandes disponibles. @@ -1247,327 +1281,566 @@ Adresse : %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Envoyer des pièces - + Send to multiple recipients at once Envoyer des pièces à plusieurs destinataires à la fois - - &Add Recipient - &Ajouter un destinataire + + Add &Recipient + Ajouter un &destinataire - + Remove all transaction fields Enlever tous les champs de transaction - + Clear &All &Tout nettoyer - + Balance: - Solde : + Solde : - + 123.456 BTC 123.456 BTC - + Confirm the send action - Confirmer l'action d'envoi + Confirmer l’action d'envoi - - &Send - &Envoyer + + S&end + E&nvoyer - + <b>%1</b> to %2 (%3) <b>%1</b> à %2 (%3) - + Confirm send coins - Confirmer l'envoi des pièces + Confirmer l’envoi des pièces - + Are you sure you want to send %1? - Êtes-vous sûr de vouloir envoyer %1 ? + Êtes-vous sûr de vouloir envoyer %1 ? - + and et - - The recepient address is not valid, please recheck. - L'adresse du destinataire n'est pas valide, veuillez la vérifier. + + The recipient address is not valid, please recheck. + Cette adresse de destinataire n’est pas valide, veuillez la vérifier. - + The amount to pay must be larger than 0. Le montant à payer doit être supérieur à 0. - + The amount exceeds your balance. Le montant dépasse votre solde. - + The total exceeds your balance when the %1 transaction fee is included. Le montant dépasse votre solde lorsque les frais de transaction de %1 sont inclus. - + Duplicate address found, can only send to each address once per send operation. Adresse dupliquée trouvée, il n'est possible d'envoyer qu'une fois à chaque adresse par opération d'envoi. - - Error: Transaction creation failed. - Erreur : échec de la création de la transaction. + + Error: Transaction creation failed! + Erreur : Échec de la création de la transaction ! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Erreur : la transaction a été rejetée. Cela peut arriver si certaines pièces de votre porte-monnaie ont déjà été dépensées, par exemple si vous avez utilisé une copie de wallet.dat avec laquelle les pièces ont été dépensées mais pas marquées comme telles ici. + Erreur : la transaction a été rejetée. Cela peut arriver si certaines pièces de votre porte-monnaie ont déjà été dépensées, par exemple si vous avez utilisé une copie de wallet.dat avec laquelle les pièces ont été dépensées mais pas marquées comme telles ici. SendCoinsEntry - + Form Formulaire - + A&mount: - &Montant : + &Montant : - + Pay &To: - Payer &à : + Payer &à : - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + L'adresse à laquelle le paiement sera envoyé (par ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book - Entrez une étiquette pour cette adresse afin de l'ajouter à votre carnet d'adresses + Entrez une étiquette pour cette adresse afin de l’ajouter à votre carnet d’adresses - + &Label: - &Étiquette : + &Étiquette : - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - L'adresse à laquelle le paiement sera envoyé (par ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Choisir une adresse dans le carnet d'adresses - + Alt+A Alt+A - + Paste address from clipboard Coller une adresse depuis le presse-papiers - + Alt+P Alt+P - + Remove this recipient Enlever ce destinataire - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Entrez une adresse Bitcoin (par ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Entrez une adresse CasinoCoin (par ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signatures - Signer / Vérifier un message + + + + &Sign Message + &Signer un message + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Vous pouvez signer des messages avec vos adresses pour prouver que les détenez. Faites attention à ne pas signer quoi que ce soit de vague car des attaques d'hameçonnage peuvent essayer d'usurper votre identité par votre signature. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous serez d'accord. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + L'adresse avec laquelle le message sera signé (par ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Choisir une adresse depuis le carnet d'adresses + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Coller une adresse depuis le presse-papiers + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Entrez ici le message que vous désirez signer + + + + Signature + Signature + + + + Copy the current signature to the system clipboard + Copier la signature actuelle dans le presse-papiers + + + + Sign the message to prove you own this CasinoCoin address + Signer le message pour prouver que vous détenez cette adresse CasinoCoin + + + + Sign &Message + Signer le &message + + + + Reset all sign message fields + Remettre à zéro tous les champs de signature de message + + + + + Clear &All + &Tout nettoyer + + + + &Verify Message + &Vérifier un message + + + + Enter the signing 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. + Entrez ci-dessous l'adresse ayant servi à signer, le message (assurez-vous d'avoir copié exactement les retours à la ligne, les espacements, 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é lui-même pour éviter d'être trompé par une attaque d'homme du milieu. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + L'adresse avec laquelle le message a été signé (par ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Vérifier le message pour vous assurer qu'il a bien été signé par l'adresse CasinoCoin spécifiée + + + + Verify &Message + Vérifier un &message + + + + Reset all verify message fields + Remettre à zéro tous les champs de vérification de message + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Entrez une adresse CasinoCoin (par ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Cliquez sur « Signer le message » pour générer la signature + + + + Enter CasinoCoin signature + Entrer une signature CasinoCoin + + + + + The entered address is invalid. + L'adresse entrée est invalide. + + + + + + + Please check the address and try again. + Veuillez vérifier l'adresse et réessayez. + + + + + The entered address does not refer to a key. + L'adresse entrée ne fait pas référence à une clef. + + + + Wallet unlock was cancelled. + Le déverrouillage du porte-monnaie a été annulé. + + + + Private key for the entered address is not available. + La clef privée pour l'adresse indiquée n'est pas disponible. + + + + Message signing failed. + La signature du message a échoué. + + + + Message signed. + Le message a été signé. + + + + The signature could not be decoded. + La signature n'a pu être décodée. + + + + + Please check the signature and try again. + Veuillez vérifier la signature et réessayez. + + + + The signature did not match the message digest. + La signature ne correspond pas au hachage du message. + + + + Message verification failed. + Échec de la vérification du message. + + + + Message verified. + Message vérifié. + + + + SplashScreen + + + The CasinoCoin developers + Les développeurs CasinoCoin + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Ouvert pour %1 blocs - - - + Open until %1 Ouvert jusqu'à %1 - - %1/offline? - %1/hors ligne ? + + %1/offline + %1/hors ligne - + %1/unconfirmed %1/non confirmée - + %1 confirmations %1 confirmations - - <b>Status:</b> - <b>État :</b> + + Status + État + + + + , broadcast through %n node(s) + , diffusée à travers %n nœud, diffusée à travers %n nœuds - + + Date + Date + + + + Source + Source + + + + Generated + Génération + + + + + From + De + + + + + + To + À + + + + + own address + votre propre adresse + + + + label + étiquette + + + + + + + + Credit + Crédit + + + + matures in %n more block(s) + arrive à maturité dans %n blocarrive à maturité dans %n blocs de plus + + + + not accepted + non accepté + + + + + + + Debit + Débit + + + + Transaction fee + Frais de transaction + + + + Net amount + Montant net + + + + Message + Message + + + + Comment + Commentaire + + + + Transaction ID + ID de la transaction + + + + Generated coins must mature 120 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. + Les pièces générées doivent mûrir pendant 120 blocs avant de pouvoir être dépensées. Lorsque vous avez généré ce bloc, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. S’il échoue a intégrer la chaîne, son état sera modifié en « non accepté » 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 avant ou après vous. + + + + Debug information + Informations de débogage + + + + Transaction + Transaction + + + + Inputs + Entrées + + + + Amount + Montant + + + + true + vrai + + + + false + faux + + + , has not been successfully broadcast yet - , n'a pas encore été diffusée avec succès + , n’a pas encore été diffusée avec succès + + + + Open for %n more block(s) + Ouvert pour %n bloc de plusOuvert pour %n blocs de plus - - , broadcast through %1 node - , diffusée à travers %1 nœud - - - - , broadcast through %1 nodes - , diffusée à travers %1 nœuds - - - - <b>Date:</b> - <b>Date :</b> - - - - <b>Source:</b> Generated<br> - <b>Source :</b> Généré<br> - - - - - <b>From:</b> - <b>De :</b> - - - + unknown inconnu - - - - - <b>To:</b> - <b>À :</b> - - - - (yours, label: - (vôtre, étiquette : - - - - (yours) - (vôtre) - - - - - - - <b>Credit:</b> - <b>Crédit : </b> - - - - (%1 matures in %2 more blocks) - (%1 sera considérée comme mûre suite à %2 blocs de plus) - - - - (not accepted) - (pas accepté) - - - - - - <b>Debit:</b> - <b>Débit : </b> - - - - <b>Transaction fee:</b> - <b>Frais de transaction :</b> - - - - <b>Net amount:</b> - <b>Montant net :</b> - - - - Message: - Message : - - - - Comment: - Commentaire : - - - - Transaction ID: - ID de la transaction : - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Les pièces générées doivent attendre 120 blocs avant de pouvoir être dépensées. Lorsque vous avez généré ce bloc, il a été diffusé sur le réseau pour être ajouté à la chaîne des blocs. S'il échoue a intégrer la chaîne, il sera modifié en « pas accepté » 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 avant ou après vous. - TransactionDescDialog - + Transaction details Détails de la transaction - + This pane shows a detailed description of the transaction Ce panneau affiche une description détaillée de la transaction @@ -1575,946 +1848,1091 @@ Adresse : %4 TransactionTableModel - + Date Date - + Type Type - + Address Adresse - + Amount Montant - - Open for %n block(s) - Ouvert pour %n blocOuvert pour %n blocs + + Open for %n more block(s) + Ouvert pour %n bloc de plusOuvert pour %n blocs de plus - + Open until %1 Ouvert jusqu'à %1 - + Offline (%1 confirmations) Hors ligne (%1 confirmations) - + Unconfirmed (%1 of %2 confirmations) Non confirmée (%1 confirmations sur un total de %2) - + Confirmed (%1 confirmations) Confirmée (%1 confirmations) - - Mined balance will be available in %n more blocks - Le solde d'extraction (mined) sera disponible dans %n blocLe solde d'extraction (mined) sera disponible dans %n blocs + + Mined balance will be available when it matures in %n more block(s) + Le solde généré (mined) sera disponible quand il aura mûri dans %n blocLe solde généré (mined) sera disponible quand il aura mûri dans %n blocs - + This block was not received by any other nodes and will probably not be accepted! - Ce bloc n'a été reçu par aucun autre nœud et ne sera probablement pas accepté ! + Ce bloc n’a été reçu par aucun autre nœud et ne sera probablement pas accepté ! - + Generated but not accepted Généré mais pas accepté - + Received with Reçue avec - + Received from Reçue de - + Sent to Envoyée à - + Payment to yourself Paiement à vous-même - + Mined Extraction - + (n/a) (indisponible) - + Transaction status. Hover over this field to show number of confirmations. État de la transaction. Laissez le pointeur de la souris sur ce champ pour voir le nombre de confirmations. - + Date and time that the transaction was received. Date et heure de réception de la transaction. - + Type of transaction. Type de transaction. - + Destination address of transaction. - L'adresse de destination de la transaction. + L’adresse de destination de la transaction. - + Amount removed from or added to balance. - Montant ajouté au ou enlevé du solde. + Montant ajouté au, ou enlevé du, solde. TransactionView - - + + All Toutes - + Today - Aujourd'hui + Aujourd’hui - + This week Cette semaine - + This month - Ce mois + Ce mois-ci - + Last month Mois dernier - + This year Cette année - + Range... - Intervalle... + Intervalle… - + Received with Reçues avec - + Sent to Envoyées à - + To yourself À vous-même - + Mined Extraction - + Other Autres - + Enter address or label to search Entrez une adresse ou une étiquette à rechercher - + Min amount Montant min - + Copy address - Copier l'adresse + Copier l’adresse - + Copy label - Copier l'étiquette + Copier l’étiquette - + Copy amount Copier le montant - - Edit label - Éditer l'étiquette + + Copy transaction ID + Copier l'ID de la transaction - + + Edit label + Éditer l’étiquette + + + Show transaction details Afficher les détails de la transaction - + Export Transaction Data Exporter les données des transactions - + Comma separated file (*.csv) Valeurs séparées par des virgules (*.csv) - + Confirmed Confirmée - + Date Date - + Type Type - + Label Étiquette - + Address Adresse - + Amount Montant - + ID ID - + Error exporting - Erreur lors de l'exportation + Erreur lors de l’exportation - + Could not write to file %1. - Impossible d'écrire sur le fichier %1. + Impossible d'écrire dans le fichier %1. - + Range: - Intervalle : + Intervalle : - + to à - - VerifyMessageDialog - - - Verify Signed Message - Vérifier le message signé - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - Entrez le message et la signature ci-dessous (faites attention à copier correctement les nouvelles lignes, les espacement, tabulations et autre caractères invisibles) pour obtenir l'adresse Bitcoin utilisée pour signer le message. - - - - Verify a message and obtain the Bitcoin address used to sign the message - Vérifier un message et obtenir l'adresse Bitcoin utilisée pour le signer - - - - &Verify Message - &Vérifier le message - - - - Copy the currently selected address to the system clipboard - Copier l'adresse surlignée dans votre presse-papiers - - - - &Copy Address - &Copier l'adresse - - - - Reset all verify message fields - Remettre à zéro tous les champs de vérification de message - - - - Clear &All - &Tout nettoyer - - - - Enter Bitcoin signature - Entrer une signature Bitcoin - - - - Click "Verify Message" to obtain address - Cliquez sur « Vérifier le message » pour obtenir l'adresse - - - - - Invalid Signature - Signature Invalide - - - - The signature could not be decoded. Please check the signature and try again. - La signature n'a pu être décodée. Veuillez la vérifier et réessayer. - - - - The signature did not match the message digest. Please check the signature and try again. - La signature ne correspond pas au hachage du message. Veuillez vérifier la signature et réessayer. - - - - Address not found in address book. - Addresse non trouvée dans l'annuaire. - - - - Address found in address book: %1 - Adresse trouvée dans le carnet d'adresses : %1 - - WalletModel - - Sending... - Envoi en cours... + + Send Coins + Envoyer des pièces - WindowOptionsPage + WalletView - - Window - Fenêtre + + &Export + &Exporter - - &Minimize to the tray instead of the taskbar - &Minimiser dans la barre système au lieu de la barre des tâches + + Export the data in the current tab to a file + Exporter les données de l'onglet courant vers un fichier - - Show only a tray icon after minimizing the window - Montrer uniquement une icône système après minimisation + + Backup Wallet + Sauvegarder le porte-monnaie - - M&inimize on close - M&inimiser lors de la fermeture + + Wallet Data (*.dat) + Données de porte-monnaie (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimiser au lieu quitter l'application lorsque la fenêtre est fermée. Lorsque cette option est activée, l'application ne pourra être fermée qu'en sélectionnant Quitter dans le menu déroulant. + + Backup Failed + Échec de la sauvegarde + + + + There was an error trying to save the wallet data to the new location. + Une erreur est survenue lors de l'enregistrement des données de porte-monnaie à un nouvel endroit + + + + Backup Successful + Sauvegarde réussie + + + + The wallet data was successfully saved to the new location. + Les données de porte-monnaie ont été enregistrées avec succès sur le nouvel emplacement. bitcoin-core - - Bitcoin version - Version de Bitcoin + + CasinoCoin version + Version de CasinoCoin - + Usage: - Utilisation : + Utilisation : - - Send command to -server or bitcoind - Envoyer une commande à -server ou à bitcoind + + Send command to -server or casinocoind + Envoyer une commande à -server ou à casinocoind - + List commands Lister les commandes - + Get help for a command - Obtenir de l'aide pour une commande + Obtenir de l’aide pour une commande - + Options: - Options : + Options : - - Specify configuration file (default: bitcoin.conf) - Spécifier le fichier de configuration (par défaut : bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Spécifier le fichier de configuration (par défaut : casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Spécifier le fichier pid (par défaut : bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Spécifier le fichier PID (par défaut : casinocoind.pid) - - Generate coins - Générer des pièces - - - - Don't generate coins - Ne pas générer de pièces - - - + Specify data directory Spécifier le répertoire de données - + Set database cache size in megabytes (default: 25) - Définir la taille du tampon en mégaoctets (par défaut :25) + Définir la taille du tampon en mégaoctets (par défaut : 25) - - Set database disk log size in megabytes (default: 100) - Définir la taille du journal de la base de données sur le disque en mégaoctets (par défaut : 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Écouter les connexions sur le <port> (par défaut : 47950 ou testnet : 17950) - - Specify connection timeout (in milliseconds) - Spécifier le délai d'expiration de la connexion (en millisecondes) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Écouter les connexions sur le <port> (par défaut : 8333 ou testnet : 18333) - - - + Maintain at most <n> connections to peers (default: 125) - Garder au plus <n> connexions avec les pairs (par défaut : 125) + Garder au plus <n> connexions avec les pairs (par défaut : 125) - - Connect only to the specified node - Ne se connecter qu'au nœud spécifié - - - + Connect to a node to retrieve peer addresses, and disconnect Se connecter à un nœud pour obtenir des adresses de pairs puis se déconnecter - + Specify your own public address Spécifier votre propre adresse publique - - Only connect to nodes in network <net> (IPv4 or IPv6) - Se connecter uniquement aux nœuds du réseau <net> (IPv4 ou IPv6) - - - - Try to discover public IP address (default: 1) - Essayer de découvrir l'adresse IP publique (par défaut : 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - Attacher à l'adresse définie. Utilisez la notation [hôte]:port pour l'IPv6 - - - + Threshold for disconnecting misbehaving peers (default: 100) - Seuil de déconnexion des pairs de mauvaise qualité (par défaut : 100) + Seuil de déconnexion des pairs de mauvaise qualité (par défaut : 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - Délai en secondes de refus de reconnexion aux pairs de mauvaise qualité (par défaut : 86400) + Délai en secondes de refus de reconnexion aux pairs de mauvaise qualité (par défaut : 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Tampon maximal de réception par connexion, <n>*1000 octets (par défaut : 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Une erreur est survenue lors de la mise en place du port RPC %u pour écouter sur IPv4 : %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Tampon maximal d'envoi par connexion, <n>*1000 octets (par défaut : 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Écouter les connexions JSON-RPC sur le <port> (par défaut : 47970 ou tesnet : 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - Détacher les bases de données des blocs et des adresses. Augmente le délai de fermeture (par défaut : 0) - - - + Accept command line and JSON-RPC commands Accepter les commandes de JSON-RPC et de la ligne de commande - + Run in the background as a daemon and accept commands Fonctionner en arrière-plan en tant que démon et accepter les commandes - + Use the test network Utiliser le réseau de test - - Output extra debugging information - Informations de débogage supplémentaires + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accepter les connexions entrantes (par défaut : 1 si -proxy ou -connect ne sont pas présents) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, vous devez définir un mot de passe rpc dans le fichier de configuration : +%s +Il vous est conseillé d'utiliser le mot de passe aléatoire suivant : +rpcuser=casinocoinrpc +rpcpassword=%s +(vous n'avez pas besoin de retenir ce mot de passe) +Le nom d'utilisateur et le mot de passe NE DOIVENT PAS être identiques. +Si le fichier n'existe pas, créez-le avec les droits de lecture accordés au propriétaire. +Il est aussi conseillé de régler alertnotify pour être prévenu des problèmes ; +par exemple : alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Une erreur est survenue lors de la mise en place du port RPC %u pour écouter sur IPv6, retour à IPv4 : %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Se lier à l'adresse donnée et toujours l'écouter. Utilisez la notation [host]:port pour l'IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Impossible d’obtenir un verrou sur le répertoire de données %s. CasinoCoin fonctionne probablement déjà. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Erreur : la transaction a été rejetée ! Cela peut arriver si certaines pièces de votre porte-monnaie étaient déjà dépensées, par exemple si vous avez utilisé une copie de wallet.dat et les pièces ont été dépensées avec cette copie sans être marquées comme telles ici. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Erreur : cette transaction nécessite des frais de transaction d'au moins %s en raison de son montant, de sa complexité ou parce que des fonds reçus récemment sont utilisés ! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Exécuter une commande lorsqu'une alerte correspondante est reçue (%s dans la commande sera remplacé par le message) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Exécuter la commande lorsqu'une transaction de porte-monnaie change (%s dans la commande est remplacée par TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Définir la taille maximale en octets des transactions prioritaires/à frais modiques (par défaut : 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Ceci est une pré-version de test - utilisez à vos risques et périls - ne l'utilisez pas pour miner ou pour des applications marchandes + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Attention : -paytxfee est réglée sur un montant très élevé ! Il s'agit des frais de transaction que vous payerez si vous émettez une transaction. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Avertissement : les transactions affichées pourraient être incorrectes ! Vous ou d'autres nœuds du réseau pourriez avoir besoin d'effectuer une mise à jour. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Attention : veuillez vérifier que l'heure et la date de votre ordinateur sont correctes ! Si votre horloge n'est pas à l'heure, CasinoCoin ne fonctionnera pas correctement. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Avertissement : une erreur est survenue lors de la lecture de wallet.dat ! Toutes les clefs ont été lues correctement mais les données de transaction ou les entrées du carnet d'adresses pourraient être incorrectes ou manquantes. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Avertissement : wallet.dat corrompu, données récupérées ! Le fichier wallet.dat original a été enregistré en tant que wallet.{horodatage}.bak dans %s ; si votre solde ou transactions sont incorrects vous devriez effectuer une restauration depuis une sauvegarde. + + + + Attempt to recover private keys from a corrupt wallet.dat + Tenter de récupérer les clefs privées d'un wallet.dat corrompu + + + + Block creation options: + Options de création des blocs : + + + + Connect only to the specified node(s) + Ne se connecter qu'au(x) nœud(s) spécifié(s) + + + + Corrupted block database detected + Base de données des blocs corrompue détectée + + + + Discover own IP address (default: 1 when listening and no -externalip) + Découvrir sa propre adresse IP (par défaut : 1 lors de l'écoute et si -externalip n'est pas présent) + + + + Do you want to rebuild the block database now? + Voulez-vous reconstruire la base de données des blocs maintenant ? + + + + Error initializing block database + Erreur lors de l'initialisation de la base de données des blocs + + + + Error initializing wallet database environment %s! + Erreur lors de l'initialisation de l'environnement de la base de données du porte-monnaie %s ! + + + + Error loading block database + Erreur du chargement de la base de données des blocs + + + + Error opening block database + Erreur lors de l'ouverture de la base de données + + + + Error: Disk space is low! + Erreur : l'espace disque est faible ! + + + + Error: Wallet locked, unable to create transaction! + Erreur : Porte-monnaie verrouillé, impossible de créer la transaction ! + + + + Error: system error: + Erreur : erreur système : + + + + Failed to listen on any port. Use -listen=0 if you want this. + Échec de l'écoute sur un port quelconque. Utilisez -listen=0 si vous voulez cela. + + + + Failed to read block info + La lecture des informations de bloc a échoué + + + + Failed to read block + La lecture du bloc a échoué + + + + Failed to sync block index + La synchronisation de l'index des blocs a échoué + + + + Failed to write block index + L''écriture de l'index des blocs a échoué + + + + Failed to write block info + L'écriture des informations du bloc a échoué + + + + Failed to write block + L'écriture du bloc a échoué + + + + Failed to write file info + L'écriture des informations de fichier a échoué + + + + Failed to write to coin database + L'écriture dans la base de données des pièces a échoué + + + + Failed to write transaction index + L'écriture de l'index des transactions a échoué + + + + Failed to write undo data + L'écriture des données d'annulation a échoué + + + + Find peers using DNS lookup (default: 1 unless -connect) + Trouver des pairs en utilisant la recherche DNS (par défaut : 1 sauf si -connect est utilisé) + + + + Generate coins (default: 0) + Générer des pièces (défaut: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Nombre de blocs à vérifier au démarrage (par défaut : 288, 0 = tout) + + + + How thorough the block verification is (0-4, default: 3) + Niveau d'approfondissement de la vérification des blocs (0-4, par défaut : 3) + + + + Not enough file descriptors available. + Pas assez de descripteurs de fichiers disponibles. + + + + Rebuild block chain index from current blk000??.dat files + Reconstruire l'index de la chaîne des blocs à partir des fichiers blk000??.dat actuels + + + + Set the number of threads to service RPC calls (default: 4) + Définir le nombre d'exétrons pour desservir les appels RPC (par défaut : 4) + + + + Verifying blocks... + Vérification des blocs... + + + + Verifying wallet... + Vérification du porte-monnaie... + + + + Imports blocks from external blk000??.dat file + Importe des blocs depuis un fichier blk000??.dat externe + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Définir le nombre de fils d’exécution pour la vérification des scripts (maximum 16, 0 = auto, < 0 = laisser ce nombre de cœurs libres, par défaut : 0) + + + + Information + Informations + + + + Invalid -tor address: '%s' + Adresse -tor invalide : « %s » + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Montant invalide pour -minrelayfee=<montant> : « %s » + + + + Invalid amount for -mintxfee=<amount>: '%s' + Montant invalide pour -mintxfee=<montant> : « %s » + + + + Maintain a full transaction index (default: 0) + Maintenir un index complet des transactions (par défaut : 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Tampon maximal de réception par -connection, <n>*1000 octets (par défaut : 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Tampon maximal d'envoi par connexion, <n>*1000 octets (par défaut : 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + N'accepter que la chaîne de blocs correspondant aux points de vérification internes (par défaut : 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Se connecter uniquement aux nœuds du réseau <net> (IPv4, IPv6 ou Tor) + + + + Output extra debugging information. Implies all other -debug* options + Afficher des information de débogage supplémentaires. Cela signifie toutes les autres options -debug* + + + + Output extra network debugging information + Afficher des informations de débogage réseau supplémentaires + + + Prepend debug output with timestamp Faire précéder les données de débogage par un horodatage - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Options SSL : (cf. le wiki de CasinoCoin pour les instructions de configuration du SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Sélectionner la version du proxy socks à utiliser (4-5, 5 étant la valeur par défaut) + + + Send trace/debug info to console instead of debug.log file Envoyer les informations de débogage/trace à la console au lieu du fichier debug.log - + Send trace/debug info to debugger Envoyer les informations de débogage/trace au débogueur - + + Set maximum block size in bytes (default: 250000) + Définir la taille maximale des blocs en octets (par défaut : 250000) + + + + Set minimum block size in bytes (default: 0) + Définir la taille minimale des blocs en octets (par défaut : 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Réduire le fichier debug.log lors du démarrage du client (par défaut : 1 lorsque -debug n'est pas présent) + + + + Signing transaction failed + La signature de la transaction a échoué + + + + Specify connection timeout in milliseconds (default: 5000) + Spécifier le délai d'expiration de la connexion en millisecondes (par défaut : 5000) + + + + System error: + Erreur système : + + + + Transaction amount too small + Montant de la transaction trop bas + + + + Transaction amounts must be positive + Les montants de la transaction doivent être positifs + + + + Transaction too large + Transaction trop volumineuse + + + + Use UPnP to map the listening port (default: 0) + Utiliser l'UPnP pour rediriger le port d'écoute (par défaut : 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Utiliser l'UPnP pour rediriger le port d'écoute (par défaut : 1 lors de l'écoute) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Utiliser un proxy pour atteindre les services cachés de Tor (par défaut : même valeur que -proxy) + + + Username for JSON-RPC connections Nom d'utilisateur pour les connexions JSON-RPC - + + Warning + Avertissement + + + + Warning: This version is obsolete, upgrade required! + Avertissement : cette version est obsolète, une mise à jour est nécessaire ! + + + + You need to rebuild the databases using -reindex to change -txindex + Vous devez reconstruire les bases de données avec -reindex pour modifier -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat corrompu, la récupération a échoué + + + Password for JSON-RPC connections Mot de passe pour les connexions JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - Écouter les connexions JSON-RPC sur le <port> (par défaut : 8332) - - - + Allow JSON-RPC connections from specified IP address Autoriser les connexions JSON-RPC depuis l'adresse IP spécifiée - + Send commands to node running on <ip> (default: 127.0.0.1) - Envoyer des commandes au nœud fonctionnant à <ip> (par défaut : 127.0.0.1) + Envoyer des commandes au nœud fonctionnant à <ip> (par défaut : 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Exécuter la commande lorsque le meilleur bloc change (%s est remplacé par le hachage du bloc dans cmd) - + Upgrade wallet to latest format Mettre à jour le format du porte-monnaie - + Set key pool size to <n> (default: 100) - Régler la taille de la plage de clefs sur <n> (par défaut : 100) + Régler la taille de la plage de clefs sur <n> (par défaut : 100) - + Rescan the block chain for missing wallet transactions Réanalyser la chaîne de blocs pour les transactions de porte-monnaie manquantes - - How many blocks to check at startup (default: 2500, 0 = all) - Nombre de blocs à tester au démarrage (par défaut : 2500, 0 = tous) - - - - How thorough the block verification is (0-6, default: 1) - Profondeur de la vérification des blocs (0-6, par défaut : 1) - - - - Imports blocks from external blk000?.dat file - Importe des blocs depuis un fichier blk000?.dat externe - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Options SSL : (cf. le wiki Bitcoin pour les réglages SSL) - - - + Use OpenSSL (https) for JSON-RPC connections Utiliser OpenSSL (https) pour les connexions JSON-RPC - + Server certificate file (default: server.cert) - Fichier de certificat serveur (par défaut : server.cert) + Fichier de certificat serveur (par défaut : server.cert) - + Server private key (default: server.pem) - Clef privée du serveur (par défaut : server.pem) + Clef privée du serveur (par défaut : server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Clefs de chiffrement acceptables (par défaut : TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Clefs de chiffrement acceptables (par défaut : TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - Attention : l'espace disque est faible - - - + This help message Ce message d'aide - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Impossible d'obtenir un verrou sur le répertoire de données %s. Bitcoin fonctionne probablement déjà. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) Impossible de se lier à %s sur cet ordinateur (bind a retourné l'erreur %d, %s) - + Connect through socks proxy Connexion via un proxy socks - - Select the version of socks proxy to use (4 or 5, 5 is default) - Sélectionner la version du proxy socks à utiliser (4 ou 5, 5 étant la valeur par défaut) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - Ne pas utiliser de proxy pour les connexions au réseau <net> (IPv4 ou IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect Autoriser les recherches DNS pour -addnode, -seednode et -connect - - Pass DNS requests to (SOCKS5) proxy - Transmettre les requêtes DNS au proxy (SOCKS5) - - - + Loading addresses... - Chargement des adresses... + Chargement des adresses… - - Error loading blkindex.dat - Erreur lors du chargement de blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted - Erreur lors du chargement de wallet.dat : porte-monnaie corrompu + Erreur lors du chargement de wallet.dat : porte-monnaie corrompu - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Erreur lors du chargement de wallet.dat : le porte-monnaie nécessite une version plus récente de Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Erreur lors du chargement de wallet.dat : le porte-monnaie nécessite une version plus récente de CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Le porte-monnaie nécessitait une réécriture. Veuillez redémarrer Bitcoin pour terminer l'opération + + Wallet needed to be rewritten: restart CasinoCoin to complete + Le porte-monnaie nécessitait une réécriture : veuillez redémarrer CasinoCoin pour terminer l'opération - + Error loading wallet.dat Erreur lors du chargement de wallet.dat - + Invalid -proxy address: '%s' - Adresse -proxy invalide : « %s » + Adresse -proxy invalide : « %s » - - Unknown network specified in -noproxy: '%s' - Le réseau spécifié dans -noproxy est inconnu : « %s » - - - + Unknown network specified in -onlynet: '%s' - Réseau inconnu spécifié sur -onlynet : « %s » + Réseau inconnu spécifié sur -onlynet : « %s » - + Unknown -socks proxy version requested: %i - Version inconnue de proxy -socks demandée : %i + Version inconnue de proxy -socks demandée : %i - + Cannot resolve -bind address: '%s' - Impossible de résoudre l'adresse -bind : « %s » + Impossible de résoudre l'adresse -bind : « %s » - - Not listening on any port - Aucune écoute sur quel port que ce soit - - - + Cannot resolve -externalip address: '%s' - Impossible de résoudre l'adresse -externalip : « %s » + Impossible de résoudre l'adresse -externalip : « %s » - + Invalid amount for -paytxfee=<amount>: '%s' - Montant invalide pour -paytxfee=<montant> : « %s » + Montant invalide pour -paytxfee=<montant> : « %s » - - Error: could not start node - Erreur : le nœud n'a pu être démarré - - - - Error: Wallet locked, unable to create transaction - Erreur : le porte-monnaie est verrouillé, impossible de créer la transaction - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Erreur : cette transaction nécessite des frais de transaction d'au moins %s en raison de son montant, de sa complexité ou parce que des fonds reçus récemment sont utilisés - - - - Error: Transaction creation failed - Erreur : échec de la création de la transaction - - - - Sending... - Envoi en cours... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Erreur : la transaction a été rejetée. Cela peut arriver si certaines pièces de votre porte-monnaie ont déjà été dépensées, par exemple si vous avez utilisé une copie de wallet.dat et si des pièces ont été dépensées avec cette copie sans être marquées comme telles ici. - - - + Invalid amount Montant invalide - + Insufficient funds Fonds insuffisants - + Loading block index... - Chargement de l'index des blocs... + Chargement de l’index des blocs… - + Add a node to connect to and attempt to keep the connection open Ajouter un nœud auquel se connecter et tenter de garder la connexion ouverte - - Unable to bind to %s on this computer. Bitcoin is probably already running. - Impossible de se lier à %s sur cet ordinateur. Bitcoin fonctionne probablement déjà. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Impossible de se lier à %s sur cet ordinateur. CasinoCoin fonctionne probablement déjà. - - Find peers using internet relay chat (default: 0) - Trouver des pairs en utilisant Internet Relay Chat (par défaut : 0) - - - - Accept connections from outside (default: 1) - Accepter les connexions entrantes (par défaut : 1) - - - - Find peers using DNS lookup (default: 1) - Trouver des pairs en utilisant la recherche DNS (par défaut : 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Utiliser Universal Plug and Play pour rediriger le port d'écoute (par défaut : 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Utiliser Universal Plug and Play pour rediriger le port d'écoute (par défaut : 0) - - - + Fee per KB to add to transactions you send Frais par Ko à ajouter aux transactions que vous enverrez - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - Attention : -paytxfee est réglée sur un montant très élevé. Il s'agit des frais de transaction que vous payerez si vous envoyez une transaction. - - - + Loading wallet... - Chargement du porte-monnaie... + Chargement du porte-monnaie… - + Cannot downgrade wallet Impossible de revenir à une version antérieure du porte-monnaie - - Cannot initialize keypool - Impossible d'initialiser le keypool - - - + Cannot write default address Impossible d'écrire l'adresse par défaut - + Rescanning... - Nouvelle analyse... + Nouvelle analyse… - + Done loading Chargement terminé - + To use the %s option Pour utiliser l'option %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, vous devez établir un mot de passe rpc dans le fichier de configuration : - %s -Il est recommandé d'utiliser le mot de passe aléatoire suivant : -rcpuser=bitcoinrpc -rpcpassword=%s -(vous n'avez pas besoin de mémoriser ce mot de passe) -Si le fichier n'existe pas, créez-le avec les droits de lecture accordés au propriétaire. - - - - + Error Erreur - - An error occured while setting up the RPC port %i for listening: %s - Une erreur est survenue lors de mise en place du port RPC d'écoute %i : %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - Vous devez ajouter la ligne rpcpassword=<mot-de-passe> au fichier de configuration : + Vous devez ajouter la ligne rpcpassword=<mot-de-passe> au fichier de configuration : %s Si le fichier n'existe pas, créez-le avec les droits de lecture seule accordés au propriétaire. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Attention : veuillez vérifier que l'heure et la date de votre ordinateur sont correctes. Si votre horloge n'est pas à l'heure, Bitcoin ne fonctionnera pas correctement. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index e3565d2..5064b71 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -3,116 +3,160 @@ AboutDialog - - About Bitcoin - A propos de Bitcoin + + About CasinoCoin + A propos de CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> version + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> version - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + +Ce logiciel est en phase expérimentale. + +Distribué sous licence MIT/X11, voir le fichier COPYING ou http://www.opensource.org/licenses/mit-license.php. + +Ce produit comprend des logiciels développés par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL (http://www.openssl.org/), un logiciel cryptographique écrit par Eric Young (eay@cryptsoft.com) et un logiciel UPnP écrit par Thomas Bernard. + + + + Copyright + + + + + The CasinoCoin developers AddressBookPage - + Address Book Carnet d'adresses - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Ceux-ci sont vos adresses Bitcoin qui vous permettent de recevoir des paiements. Vous pouvez en donner une différente à chaque expédieur afin de savoir qui vous payent. - - - + Double-click to edit address or label Double-cliquez afin de modifier l'adress ou l'étiquette - + Create a new address Créer une nouvelle adresse - + Copy the currently selected address to the system clipboard Copier l'adresse surligné a votre presse-papier - + &New Address - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Ceux-ci sont vos adresses CasinoCoin qui vous permettent de recevoir des paiements. Vous pouvez en donner une différente à chaque expédieur afin de savoir qui vous payent. + + + &Copy Address - + Show &QR Code - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address - - &Sign Message + + Sign &Message - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Supprimer l'adresse sélectionnée dans la liste. Seules les adresses d'envoi peuvent être supprimé. + + Delete the currently selected address from the list + - + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete &Supprimer - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + &Edit - + + Send &Coins + + + + Export Address Book Data Exporter les données du carnet d'adresses - + Comma separated file (*.csv) - + Error exporting - + Could not write to file %1. @@ -120,17 +164,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label - + Address - + (no label) @@ -138,431 +182,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase - + New passphrase - + Repeat new passphrase - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - + Encrypt wallet - + This operation needs your wallet passphrase to unlock the wallet. - + Unlock wallet - + This operation needs your wallet passphrase to decrypt the wallet. - + Decrypt wallet - + Change passphrase - + Enter the old and new passphrase to the wallet. - + Confirm wallet encryption - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! - - + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted - - Bitcoin 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. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - - + + The supplied passphrases do not match. - + Wallet unlock failed - - - + + + The passphrase entered for the wallet decryption was incorrect. - + Wallet decryption failed - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. BitcoinGUI - - Bitcoin Wallet - - - - + Sign &message... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... - + &Overview - + Show general overview of wallet - + &Transactions - + Browse transaction history - - &Address Book - - - - + Edit the list of stored addresses and labels - - &Receive coins - - - - + Show the list of addresses for receiving payments - - &Send coins - - - - - Prove you control an address - - - - + E&xit - + Quit application - - &About %1 + + Show information about CasinoCoin - - Show information about Bitcoin - - - - + About &Qt - + Show information about Qt - + &Options... - + &Encrypt Wallet... - + &Backup Wallet... - + &Change Passphrase... - - - ~%n block(s) remaining - - - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... + + Reindexing blocks on disk... - - Send coins to a Bitcoin address + + Send coins to a CasinoCoin address - - Modify configuration options for Bitcoin + + Modify configuration options for CasinoCoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - - - - + Backup wallet to another location - + Change the passphrase used for wallet encryption - + &Debug window - + Open debugging and diagnostic console - + &Verify message... - - Verify a message signature + + + CasinoCoin - + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + &A propos de CasinoCoin + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File - + &Settings - + &Help - + Tabs toolbar - - Actions toolbar - - - - - + + [testnet] - - - Bitcoin client + + CasinoCoin client - - %n active connection(s) to Bitcoin network + + %n active connection(s) to CasinoCoin network - - Downloaded %1 blocks of transaction history. + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. - - %n second(s) ago + + %n hour(s) - - %n minute(s) ago + + %n day(s) - - %n hour(s) ago - - - - - %n day(s) ago + + %n week(s) - + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date - + Catching up... - - Last received block was generated %1. - - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - - - - + Confirm transaction fee - + Sent transaction - + Incoming transaction - + Date: %1 Amount: %2 Type: %3 @@ -571,538 +644,485 @@ Address: %4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address - + &Label - + The label associated with this address book entry - + &Address - + The address associated with this address book entry. This can only be modified for sending addresses. - + New receiving address - + New sending address - + Edit receiving address - + Edit sending address - + The entered address "%1" is already in the address book. - - The entered address "%1" is not a valid Bitcoin address. + + The entered address "%1" is not a valid CasinoCoin address. - + Could not unlock wallet. - + New key generation failed. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + Usage: - - options + + command-line options - + UI options - + Set language, for example "de_DE" (default: system locale) - + Start minimized - + Show splash screen on startup (default: 1) - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - - - - - Main - - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - - &Connect through SOCKS4 proxy: - - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - - - - - Port of the proxy (e.g. 1234) - - - OptionsDialog - + Options + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + OverviewPage - + Form - - - 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - + Balance: - - Number of transactions: - - - - + Unconfirmed: - + Wallet - + + Immature: + + + + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> - + Your current balance - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - - Total number of transactions in wallet + + + out of sync + + + PaymentServer - - - out of sync + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - - QR Code - - - - + Request Payment - + Amount: - - BTC - - - - + Label: - + Message: - + &Save As... - + Error encoding URI into QR Code. - + + The entered amount is invalid, please check. + + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + PNG Images (*.png) @@ -1110,125 +1130,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Number of connections - + On testnet - + Block chain - + Current number of blocks - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1236,109 +1277,109 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - + Send to multiple recipients at once - - &Add Recipient + + Add &Recipient - + Remove all transaction fields - + Clear &All - + Balance: - + 123.456 BTC - + Confirm the send action - - &Send + + S&end - + <b>%1</b> to %2 (%3) - + Confirm send coins - + Are you sure you want to send %1? - + and - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. - + The amount to pay must be larger than 0. - + The amount exceeds your balance. - + The total exceeds your balance when the %1 transaction fee is included. - + Duplicate address found, can only send to each address once per send operation. - - Error: Transaction creation failed. + + Error: Transaction creation failed! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -1346,217 +1387,456 @@ Address: %4 SendCoinsEntry - + Form - + A&mount: - + Pay &To: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book - + &Label: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - + Choose address from address book - + Alt+A - + Paste address from clipboard - + Alt+P - + Remove this recipient - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] TransactionDesc - - Open for %1 blocks - - - - + Open until %1 - - %1/offline? + + %1/offline - + %1/unconfirmed - + %1 confirmations - - <b>Status:</b> + + Status + + + + + , broadcast through %n node(s) + + + + + Date - + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + , has not been successfully broadcast yet - - - , broadcast through %1 node - + + + Open for %n more block(s) + - - , broadcast through %1 nodes - - - - - <b>Date:</b> - - - - - <b>Source:</b> Generated<br> - - - - - - <b>From:</b> - - - - + unknown - - - - - <b>To:</b> - - - - - (yours, label: - - - - - (yours) - - - - - - - - <b>Credit:</b> - - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - - - - - - - <b>Debit:</b> - - - - - <b>Transaction fee:</b> - - - - - <b>Net amount:</b> - - - - - Message: - - - - - Comment: - - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - - TransactionDescDialog - + Transaction details - + This pane shows a detailed description of the transaction @@ -1564,117 +1844,117 @@ Address: %4 TransactionTableModel - + Date - + Type - + Address - + Amount - - Open for %n block(s) + + Open for %n more block(s) - + Open until %1 - + Offline (%1 confirmations) - + Unconfirmed (%1 of %2 confirmations) - + Confirmed (%1 confirmations) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) - + This block was not received by any other nodes and will probably not be accepted! - + Generated but not accepted - + Received with - + Received from - + Sent to - + Payment to yourself - + Mined - + (n/a) - + Transaction status. Hover over this field to show number of confirmations. - + Date and time that the transaction was received. - + Type of transaction. - + Destination address of transaction. - + Amount removed from or added to balance. @@ -1682,818 +1962,961 @@ Address: %4 TransactionView - - + + All - + Today - + This week - + This month - + Last month - + This year - + Range... - + Received with - + Sent to - + To yourself - + Mined - + Other - + Enter address or label to search - + Min amount - + Copy address - + Copy label - + Copy amount - + + Copy transaction ID + + + + Edit label - + Show transaction details - + Export Transaction Data - + Comma separated file (*.csv) - + Confirmed - + Date - + Type - + Label - + Address - + Amount - + ID - + Error exporting - + Could not write to file %1. - + Range: - + to - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copier l'adresse surligné a votre presse-papier - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... + + Send Coins - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file - - Show only a tray icon after minimizing the window + + Backup Wallet - - M&inimize on close + + Wallet Data (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. bitcoin-core - - Bitcoin version + + CasinoCoin version - + Usage: - - Send command to -server or bitcoind + + Send command to -server or casinocoind - + List commands - + Get help for a command - + Options: - - Specify configuration file (default: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Set database cache size in megabytes (default: 25) - - Set database disk log size in megabytes (default: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands - + Use the test network - - Output extra debugging information + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - - - - - Sending... - - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + Error - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts new file mode 100644 index 0000000..cc103c2 --- /dev/null +++ b/src/qt/locale/bitcoin_gu_IN.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + બીટકોઈન વિષે + + + + <b>CasinoCoin</b> version + + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + + + + + Double-click to edit address or label + + + + + Create a new address + + + + + Copy the currently selected address to the system clipboard + + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + + + + + Comma separated file (*.csv) + + + + + Error exporting + + + + + Could not write to file %1. + + + + + AddressTableModel + + + Label + + + + + Address + + + + + (no label) + + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + + + + + New passphrase + + + + + Repeat new passphrase + + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + + + + + Encrypt wallet + + + + + This operation needs your wallet passphrase to unlock the wallet. + + + + + Unlock wallet + + + + + This operation needs your wallet passphrase to decrypt the wallet. + + + + + Decrypt wallet + + + + + Change passphrase + + + + + Enter the old and new passphrase to the wallet. + + + + + Confirm wallet encryption + + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + + + + The supplied passphrases do not match. + + + + + Wallet unlock failed + + + + + + + The passphrase entered for the wallet decryption was incorrect. + + + + + Wallet decryption failed + + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + + + + + &Overview + + + + + Show general overview of wallet + + + + + &Transactions + + + + + Browse transaction history + + + + + Edit the list of stored addresses and labels + + + + + Show the list of addresses for receiving payments + + + + + E&xit + + + + + Quit application + + + + + Show information about CasinoCoin + + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + + + + + &Settings + + + + + &Help + + + + + Tabs toolbar + + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + + + + + Address + + + + + Amount + + + + + ID + + + + + Error exporting + + + + + Could not write to file %1. + + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 224bf54..1e96b09 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - אודות ביטקוין + + About CasinoCoin + אודות לייטקוין - - <b>Bitcoin</b> version - גרסת <b>ביטקוין</b> + + <b>CasinoCoin</b> version + גרסת <b>לייטקוין</b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - זכויות יוצרים © 2009-2012 שמורות למפתחי ביטקוין - + זוהי תוכנה ניסיונית. -מופץ תחת רישיון תוכנה MIT/X11, ראה את הקובץ המלווה license.txt או http://www.opensource.org/licenses/mit-license.php. +מופצת תחת רישיון התוכנה MIT/X11, ראה את הקובץ המצורף COPYING או http://www.opensource.org/licenses/mit-license.php. -המוצר הזה כולל תוכנה שפותחה על ידי פרויקט OpenSSL עבור שימוש בערכת הכלים של OpenSSL (http://www.openssl.org/) ובתוכנה קריפטוגרפית שנכתבה על ידי אריק יאנג (eay@cryptsoft.com) ותוכנת UPnP שנכתבה על ידי תומס ברנרד. +המוצר הזה כולל תוכנה שפותחה ע"י פרויקט OpenSSL לשימוש בתיבת הכלים OpenSSL (http://www.openssl.org/) ותוכנה קריפטוגרפית שנכתבה ע"י אריק יאנג (eay@cryptsoft.com) ותוכנת UPnP שנכתבה ע"י תומס ברנרד. + + + + Copyright + זכויות יוצרים + + + + The CasinoCoin developers + AddressBookPage - + Address Book פנקס כתובות - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - אלה כתובות הביטקוין שלך עבור קבלת תשלומים. אתה עשוי לרצות לתת כתובת שונה לכל שולח כדי שתוכל לעקוב אחר מי משלם לך. - - - + Double-click to edit address or label לחץ לחיצה כפולה לערוך כתובת או תוית - + Create a new address יצירת כתובת חדשה - + Copy the currently selected address to the system clipboard העתק את הכתובת המסומנת ללוח העריכה - + &New Address - + כתובת חדשה - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + אלה כתובת הלייטקוין שלך עבור קבלת תשלומים. ייתכן ותרצה לתת כתובת שונה לכל שולח כדי שתוכל לעקוב אחר מי משלם לך. + + + &Copy Address - + העתק כתובת - + Show &QR Code הצג &קוד QR - - Sign a message to prove you own this address - חתום על הודעה כדי להוכיח שכתובת זו בבעלותך + + Sign a message to prove you own a CasinoCoin address + חתום על הודעה בכדי להוכיח כי אתה הבעלים של כתובת לייטקוין. - - &Sign Message - חתום על הו&דעה + + Sign &Message + חתום על הודעה - - Delete the currently selected address from the list. Only sending addresses can be deleted. - מחק את הכתובת המסומנת מהרשימה. ניתן למחוק רק כתובות לשליחה. + + Delete the currently selected address from the list + מחק את הכתובת שנבחרה מהרשימה - + + Export the data in the current tab to a file + יצוא הנתונים בטאב הנוכחי לקובץ + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + אמת הודעה בכדי להבטיח שהיא נחתמה עם כתובת לייטקוין מסוימת. + + + + &Verify Message + אמת הודעה + + + &Delete - &מחיקה + מחק - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + אלה כתובת הלייטקוין שלך עבור שליחת תשלומים. תמיד בדוק את מספר ואת כתובות מקבלי התשלומים לפני שליחת מטבעות. + + + Copy &Label - + העתק תוית - + &Edit - + עריכה - + + Send &Coins + שלח מטבעות + + + Export Address Book Data יצוא נתוני פנקס כתובות - + Comma separated file (*.csv) קובץ מופרד בפסיקים (*.csv) - + Error exporting שגיאה ביצוא - + Could not write to file %1. לא מסוגל לכתוב לקובץ %1. @@ -126,450 +164,478 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label תוית - + Address כתובת - + (no label) - (ללא כתובת) + (ללא תוית) AskPassphraseDialog - + Passphrase Dialog - + שיח סיסמא - + Enter passphrase הכנס סיסמא - + New passphrase סיסמה חדשה - + Repeat new passphrase חזור על הסיסמה החדשה - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. הכנס את הסיסמה החדשה לארנק. <br/>אנא השתמש בסיסמה המכילה <b>10 תוים אקראיים או יותר</b>, או <b>שמונה מילים או יותר</b>. - + Encrypt wallet - הצפנת ארנק + הצפן ארנק - + This operation needs your wallet passphrase to unlock the wallet. הפעולה הזו דורשת את סיסמת הארנק שלך בשביל לפתוח את הארנק. - + Unlock wallet פתיחת ארנק - + This operation needs your wallet passphrase to decrypt the wallet. הפעולה הזו דורשת את סיסמת הארנק שלך בשביל לפענח את הארנק. - + Decrypt wallet פענוח ארנק - + Change passphrase שינוי סיסמה - + Enter the old and new passphrase to the wallet. הכנס את הסיסמות הישנה והחדשה לארנק. - + Confirm wallet encryption אשר הצפנת ארנק - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - אזהרה: אם תצפין את הארנק שלך ותאבד את הסיסמה אתה <b>תאבד את כל הביטקוין שלך</b>! -אתה בטוח שברצונך להצפין את הארנק? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + אזהרה: אם אתה מצפין את הארנק ומאבד את הסיסמא, אתה <b>תאבד את כל הלייטקוינים שלך</b>! - - + + Are you sure you wish to encrypt your wallet? + האם אתה בטוח שברצונך להצפין את הארנק? + + + + 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. + חשוב! כל גיבוי קודם שעשית לארנק שלך יש להחליף עם קובץ הארנק המוצפן שזה עתה נוצר. מסיבות אבטחה, גיבויים קודמים של קובץ הארנק הלא-מוצפן יהפכו לחסרי שימוש ברגע שתתחיל להשתמש בארנק החדש המוצפן. + + + + + Warning: The Caps Lock key is on! + זהירות: מקש Caps Lock מופעל! + + + + Wallet encrypted הארנק הוצפן - - Bitcoin 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. - ביטקוין ייסגר עכשיו כדי להשלים את תהליך ההצפנה. זכור שהצפנת הארנק שלך אינו יכול להגן באופן מלא על הביטקוינים שלך מתוכנות זדוניות המושתלות על המחשב. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + לייטקוין ייסגר עכשיו כדי להשלים את תהליך ההצפנה. זכור שהצפנת הארנק שלך אינו יכול להגן באופן מלא על הלייטקוינים שלך מתוכנות זדוניות המושתלות על המחשב. - - - Warning: The Caps Lock key is on. - אזהרה: מקש Caps Lock מופעל. - - - - - - + + + + Wallet encryption failed הצפנת הארנק נכשלה - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. הצפנת הארנק נכשלה עקב שגיאה פנימית. הארנק שלך לא הוצפן. - - + + The supplied passphrases do not match. הסיסמות שניתנו אינן תואמות. - + Wallet unlock failed פתיחת הארנק נכשלה - - - + + + The passphrase entered for the wallet decryption was incorrect. הסיסמה שהוכנסה לפענוח הארנק שגויה. - + Wallet decryption failed פענוח הארנק נכשל - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. סיסמת הארנק שונתה בהצלחה. BitcoinGUI - - Bitcoin Wallet - ארנק ביטקוין - - - + Sign &message... - + חתום על הודעה - - Show/Hide &Bitcoin - הצג/הסתר את &ביטקוין - - - + Synchronizing with network... מסתנכרן עם הרשת... - + &Overview &סקירה - + Show general overview of wallet הצג סקירה כללית של הארנק - + &Transactions &פעולות - + Browse transaction history דפדף בהיסטוריית הפעולות - - &Address Book - פנקס &כתובות - - - + Edit the list of stored addresses and labels ערוך את רשימת הכתובות והתויות - - &Receive coins - &קבלת מטבעות - - - + Show the list of addresses for receiving payments הצג את רשימת הכתובות לקבלת תשלומים - - &Send coins - &שלח מטבעות - - - - Prove you control an address - הוכח שאתה שולט בכתובת - - - + E&xit י&ציאה - + Quit application סגור תוכנה - - &About %1 - &אודות %1 + + Show information about CasinoCoin + הצג מידע על לייטקוין - - Show information about Bitcoin - הצג מידע על ביטקוין - - - + About &Qt אודות Qt - + Show information about Qt הצג מידע על Qt - + &Options... &אפשרויות - + &Encrypt Wallet... - + הצפן ארנק - + &Backup Wallet... - + גיבוי ארנק - + &Change Passphrase... - - - - - ~%n block(s) remaining - בלוק אחד נותר~%n בלוקים נותרו + שנה סיסמא - - Downloaded %1 of %2 blocks of transaction history (%3% done). - הורדו %1 בלוקים של היסטוריית פעולות מתוך %2 (הושלם %3% מהסה"כ). + + Importing blocks from disk... + מייבא בלוקים מהדיסק... - - &Export... - י&צא לקובץ + + Reindexing blocks on disk... + מחדש את אינדקס הבלוקים בדיסק... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + שלח מטבעות לכתובת לייטקוין - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + שנה אפשרויות תצורה עבור לייטקוין - - Show or hide the Bitcoin window - הצג או הסתר את חלון ביטקוין. - - - - Export the data in the current tab to a file - יצוא הנתונים בטאב הנוכחי לקובץ - - - - Encrypt or decrypt wallet - הצפן או פענח ארנק - - - + Backup wallet to another location גיבוי הארנק למקום אחר - + Change the passphrase used for wallet encryption שנה את הסיסמה להצפנת הארנק - + &Debug window - + חלון ניפוי - + Open debugging and diagnostic console - + פתח את לוח הבקרה לאבחון וניפוי - + &Verify message... - + אמת הודעה... - - Verify a message signature - + + + CasinoCoin + לייטקוין - + + Wallet + ארנק + + + + &Send + ושלח + + + + &Receive + וקבל + + + + &Addresses + וכתובות + + + + &About CasinoCoin + אודות לייטקוין + + + + &Show / Hide + הצג / הסתר + + + + Show or hide the main Window + הצג או הסתר את החלון הראשי + + + + Encrypt the private keys that belong to your wallet + הצפן את המפתחות הפרטיים ששייכים לארנק שלך + + + + Sign messages with your CasinoCoin addresses to prove you own them + חתום על הודעות עם כתובות הלייטקוין שלך כדי להוכיח שהן בבעלותך + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + אמת הודעות כדי להבטיח שהן נחתמו עם כתובת לייטקוין מסוימות + + + &File &קובץ - + &Settings ה&גדרות - + &Help &עזרה - + Tabs toolbar סרגל כלים טאבים - - Actions toolbar - סרגל כלים פעולות - - - - + + [testnet] [רשת-בדיקה] - - - Bitcoin client - תוכנת ביטקוין + + CasinoCoin client + תוכנת לייטקוין - - %n active connection(s) to Bitcoin network - חיבור פעיל אחד לרשת הביטקוין%n חיבורים פעילים לרשת הביטקוין + + %n active connection(s) to CasinoCoin network + חיבור פעיל אחד לרשת הלייטקוין%n חיבורים פעילים לרשת הלייטקוין - - Downloaded %1 blocks of transaction history. - הורדו %1 בלוקים של היסטוריית פעולות. - - - - %n second(s) ago - לפני שניהלפני %n שניות - - - - %n minute(s) ago - לפני דקהלפני %n דקות - - - - %n hour(s) ago - לפני שעהלפני %n שעות - - - - %n day(s) ago - לפני יוםלפני %n ימים + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + 1% מתוך 2% (משוער) בלוקים של הסטוריית פעולת עובדו + + + + Processed %1 blocks of transaction history. + הושלם עיבוד של %1 בלוקים של היסטוריית פעולות. + + + + %n hour(s) + %n שעה%n שעות + + + + %n day(s) + %n יום%n ימים + + + + %n week(s) + %n שבוע%n שבועות + + + + %1 behind + 1% מאחור + + + + Last received block was generated %1 ago. + הבלוק האחרון שהתקבל נוצר לפני %1 + + + + Transactions after this will not yet be visible. + לאחר זאת פעולות נספות טרם יהיו גלויות + + + + Error + שגיאה + + + + Warning + אזהרה + + + + Information + מידע + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + פעולה זו חורגת מגבולות הגודל. עדיין באפשרותך לשלוח אותה תמורת עמלה של %1, המיועדת לצמתים שמעבדים את הפעולה שלך ועוזרת לתמוך ברשת. האם ברצונך לשלם את העמלה? + + + Up to date עדכני - + Catching up... מתעדכן... - - Last received block was generated %1. - הבלוק האחרון שהתקבל נוצר ב-%1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - הפעולה הזאת חורגת מהמגבלה. ניתן לשלוח אותה תמורת עמלה בסך %1, שמגיעה לצמתים שמעבדים את הפעולה ועוזרת לתמוך ברשת. האם אתה מעוניין לשלם את העמלה? - - - + Confirm transaction fee - + אשר עמלת פעולה - + Sent transaction פעולה שנשלחה - + Incoming transaction פעולה שהתקבלה - + Date: %1 Amount: %2 Type: %3 @@ -581,538 +647,485 @@ Address: %4 כתובת: %4 - + + + URI handling + תפעול URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + לא ניתן לנתח URI! זה יכול להיגרם כתוצאה מכתובת לייטקוין לא תקינה או פרמטרי URI חסרי צורה תקינה. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> הארנק <b>מוצפן</b> וכרגע <b>פתוח</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> הארנק <b>מוצפן</b> וכרגע <b>נעול</b> - - Backup Wallet - גיבוי ארנק - - - - Wallet Data (*.dat) - נתוני ארנק (*.dat) - - - - Backup Failed - הגיבוי נכשל - - - - There was an error trying to save the wallet data to the new location. - היתה שגיאה בניסיון לשמור את מידע הארנק למיקום החדש. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + שגיאה סופנית אירעה. לייטקוין אינו יכול להמשיך לפעול בבטחה ולכן ייסגר. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - תצוגה - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - בחר את יחידת החלוקה להצגה בממשק, ובעת שליחת מטבעות - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + אזעקת רשת EditAddressDialog - + Edit Address ערוך כתובת - + &Label ת&וית - + The label associated with this address book entry התוית המשויכת לרשומה הזו בפנקס הכתובות - + &Address &כתובת - + The address associated with this address book entry. This can only be modified for sending addresses. הכתובת המשויכת לרשומה זו בפנקס הכתובות. ניתן לשנות זאת רק עבור כתובות לשליחה. - + New receiving address כתובת חדשה לקבלה - + New sending address כתובת חדשה לשליחה - + Edit receiving address ערוך כתובת לקבלה - + Edit sending address ערוך כתובת לשליחה - + The entered address "%1" is already in the address book. הכתובת שהכנסת "%1" כבר נמצאת בפנקס הכתובות. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + הכתובת שהוכנסה "%1" אינה כתובת לייטקוין תקינה. - + Could not unlock wallet. פתיחת הארנק נכשלה. - + New key generation failed. יצירת מפתח חדש נכשלה. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + גרסה - + Usage: שימוש: - - options - + + command-line options + אפשרויות שורת פקודה - + UI options - + אפשרויות ממשק - + Set language, for example "de_DE" (default: system locale) קבע שפה, למשל "he_il" (ברירת מחדל: שפת המערכת) - + Start minimized התחל ממוזער - + Show splash screen on startup (default: 1) הצג מסך פתיחה בעת הפעלה (ברירת מחדל: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + אפשרויות + + + + &Main + ראשי + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee שלם &עמלת פעולה - - Main - ראשי + + Automatically start CasinoCoin after logging in to the system. + הפעל את לייטקוין באופן עצמאי לאחר התחברות למערכת. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - עמלת פעולה אופציונלית לכל kB תבטיח שהפעולה שלך תעובד בזריזות. רוב הפעולות הן 1 kB. מומלצת עמלה בסך 0.01. + + &Start CasinoCoin on system login + התחל את לייטקוין בעת התחברות למערכת - - &Start Bitcoin on system login - + + Reset all client options to default. + אפס כל אפשרויות התוכנה לברירת המחדל. - - Automatically start Bitcoin after logging in to the system - + + &Reset Options + איפוס אפשרויות - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + רשת - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - אתה יכול לחתום על הודעות עם הכתובות שלך כדי להוכיח שהן בבעלותך. היזהר לא לחתום על משהו מעורפל, שכן התקפות פישינג עשויות לגרום לך בעורמה למסור את זהותך. חתום רק על אמרות מפורטות לחלוטין שאתה מסכים עימן. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + פתח את פורט לייטקוין בנתב באופן אוטומטי. עובד רק אם UPnP מאופשר ונתמך ע"י הנתב. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - הכתובת המשמשת לחתימה על ההודעה (למשל 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - בחר כתובת מפנקס הכתובות - - - - Alt+A - Alt+A - - - - Paste address from clipboard - הדבק כתובת מהלוח - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - הכנס כאן את ההודעה שעליך ברצונך לחתום - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - לחץ על "חתום על הודעה" לקבלת חתימה - - - - Sign a message to prove you own this address - חתום על הודעה כדי להוכיח שכתובת זו בבעלותך - - - - &Sign Message - חתום על הו&דעה - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - הכנס כתובת ביטקוין (למשל 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - שגיאה בחתימה - - - - %1 is not a valid address. - %1 אינה כתובת תקינה. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - המפתח הפרטי עבור %1 אינו זמין. - - - - Sign failed - החתימה נכשלה - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP מיפוי פורט באמצעות UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - פתח את פורט ביטקוין בנתב באופן אוטומטי. עובד רק אם UPnP מאופשר ונתמך ע"י הנתב. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + התחבר לרשת הלייטקוין דרך פרוקסי SOCKS (למשל בעת התחברות דרך Tor). - - &Connect through SOCKS4 proxy: - התח&בר דרך פרוקסי SOCKS4: + + &Connect through SOCKS proxy: + התחבר דרך פרוקסי SOCKS - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - התחבר לרשת הביטקוין דרך פרוקסי SOCKS4 (למשל, בעת חיבור דרך Tor) - - - + Proxy &IP: - + כתובת IP של פרוקסי: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) כתובת האינטרנט של הפרוקסי (למשל 127.0.0.1) - - Port of the proxy (e.g. 1234) - הפורט של הפרוקסי (למשל 1234) + + &Port: + פורט: - - - OptionsDialog - - Options - אפשרויות + + Port of the proxy (e.g. 9050) + הפורט של הפרוקסי (למשל 9050) + + + + SOCKS &Version: + גרסת SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + גרסת SOCKS של הפרוקסי (למשל 5) + + + + &Window + חלון + + + + Show only a tray icon after minimizing the window. + הצג סמל מגש בלבד לאחר מזעור החלון. + + + + &Minimize to the tray instead of the taskbar + מ&זער למגש במקום לשורת המשימות + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + מזער את התוכנה במקום לצאת ממנה כשהחלון נסגר. כשאפשרות זו פעילה, התוכנה תיסגר רק לאחר בחירת יציאה מהתפריט. + + + + M&inimize on close + מזער בעת סגירה + + + + &Display + תצוגה + + + + User Interface &language: + שפת ממשק המשתמש: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + ניתן לקבוע כאן את שפת ממשק המשתמש. הגדרה זו תחול לאחר הפעלה מחדש של לייטקוין. + + + + &Unit to show amounts in: + יחידת מדידה להצגת כמויות: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + בחר את ברירת המחדל ליחידת החלוקה אשר תוצג בממשק ובעת שליחת מטבעות. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + האם להציג כתובות לייטקוין ברשימת הפעולות או לא. + + + + &Display addresses in transaction list + הצג כתובות ברשימת הפעולות + + + + &OK + אישור + + + + &Cancel + ביטול + + + + &Apply + יישום + + + + default + ברירת מחדל + + + + Confirm options reset + אשר את איפוס האפשרויות + + + + Some settings may require a client restart to take effect. + כמה מההגדרות עשויות לדרוש אתחול התוכנה כדי להיכנס לפועל. + + + + Do you want to proceed? + האם ברצונך להמשיך? + + + + + Warning + אזהרה + + + + + This setting will take effect after restarting CasinoCoin. + הגדרה זו תחול לאחר הפעלה מחדש של לייטקוין. + + + + The supplied proxy address is invalid. + כתובת הפרוקסי שסופקה אינה תקינה. OverviewPage - + Form טופס - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + המידע המוצג עשוי להיות מיושן. הארנק שלך מסתנכרן באופן אוטומטי עם רשת הלייטקוין לאחר כינון חיבור, אך התהליך טרם הסתיים. - + Balance: יתרה: - - Number of transactions: - מספר פעולות: - - - + Unconfirmed: ממתין לאישור: - + Wallet - + ארנק - + + Immature: + לא בשל: + + + + Mined balance that has not yet matured + מאזן שנכרה וטרם הבשיל + + + <b>Recent transactions</b> <b>פעולות אחרונות</b> - + Your current balance היתרה הנוכחית שלך - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance הסכום הכולל של פעולות שטרם אושרו, ועוד אינן נספרות בחישוב היתרה הנוכחית - - Total number of transactions in wallet - המספר הכולל של פעולות בארנק - - - - + + out of sync - + לא מסונכרן + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + לא ניתן להתחיל את לייטקוין: מפעיל לחץ-לתשלום QRCodeDialog - + QR Code Dialog - + שיח קוד QR - - QR Code - קוד QR - - - + Request Payment בקש תשלום - + Amount: כמות: - - BTC - ביטקוין - - - + Label: תוית: - + Message: הודעה: - + &Save As... &שמור בשם... - + Error encoding URI into QR Code. - + שגיאה בקידוד URI לקוד QR - + + The entered amount is invalid, please check. + הכמות שהוכנסה אינה תקינה, אנא ודא. + + + Resulting URI too long, try to reduce the text for label / message. המזהה המתקבל ארוך מדי, נסה להפחית את הטקסט בתוית / הודעה. - + Save QR Code - + שמור קוד QR - + PNG Images (*.png) תמונות PNG (*.png) @@ -1120,453 +1133,713 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + שם ממשק - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + גרסת ממשק - + &Information - + מידע - - Client - + + Using OpenSSL version + משתמש ב-OpenSSL גרסה - + Startup time - + זמן אתחול - + Network - + רשת - + Number of connections - + מספר חיבורים - + On testnet - + ברשת הבדיקה - + Block chain - + שרשרת הבלוקים - + Current number of blocks - + מספר הבלוקים הנוכחי - + Estimated total blocks - + מספר כולל משוער של בלוקים - + Last block time - + זמן הבלוק האחרון - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + פתח - + + Command-line options + אפשרויות שורת פקודה + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + הצג את הודעה העזרה של casinocoin-qt כדי לקבל רשימה של אפשרויות שורת פקודה של לייטקוין. + + + + &Show + הצג + + + &Console - + לוח בקרה - + Build date - + תאריך בניה - + + CasinoCoin - Debug window + לייטקוין - חלון ניפוי + + + + CasinoCoin Core + ליבת לייטקוין + + + + Debug log file + קובץ יומן ניפוי + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + פתח את קובץ יומן הניפוי מתיקיית הנתונים הנוכחית. זה עשוי לקחת מספר שניות עבור קובצי יומן גדולים. + + + Clear console - + נקה לוח בקרה - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + ברוכים הבאים ללוח בקרת RPC של לייטקוין - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + השתמש בחיצים למעלה ולמטה כדי לנווט בהיסטוריה, ו- <b>Ctrl-L</b> כדי לנקות את המסך. - + Type <b>help</b> for an overview of available commands. - + הקלד <b>help</b> בשביל סקירה של הפקודות הזמינות. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins שלח מטבעות - + Send to multiple recipients at once שלח למספר מקבלים בו-זמנית - - &Add Recipient - + + Add &Recipient + הוסף מקבל - + Remove all transaction fields הסר את כל השדות בפעולה - + Clear &All - + נקה הכל - + Balance: יתרה: - + 123.456 BTC - 123.456 ביטקוין + 123.456 לייטקוין - + Confirm the send action אשר את פעולת השליחה - - &Send - &שלח + + S&end + שלח - + <b>%1</b> to %2 (%3) <b>%1</b> ל- %2 (%3) - + Confirm send coins אשר שליחת מטבעות - + Are you sure you want to send %1? האם אתה בטוח שברצונך לשלוח %1? - + and ו- - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. כתובת המקבל אינה תקינה, אנא בדוק שנית. - + The amount to pay must be larger than 0. הכמות לשלם חייבת להיות גדולה מ-0. - + The amount exceeds your balance. - + הכמות עולה על המאזן שלך. - + The total exceeds your balance when the %1 transaction fee is included. - + הכמות הכוללת, ובכללה עמלת פעולה בסך %1, עולה על המאזן שלך. - + Duplicate address found, can only send to each address once per send operation. - + כתובת כפולה נמצאה, ניתן לשלוח לכל כתובת רק פעם אחת בכל פעולת שליחה. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + שגיאה: יצירת הפעולה נכשלה! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + שגיאה: הפעולה נדחתה. זה עשוי לקרות עם חלק מהמטבעות בארנק שלך כבר נוצלו, למשל אם השתמשת בעותק של wallet.dat ומטבעות נוצלו בעותק אך לא סומנו כמנוצלות כאן. SendCoinsEntry - + Form טופס - + A&mount: כ&מות: - + Pay &To: שלם &ל: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + הכתובת שאליה ישלח התשלום (למשל Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book הכנס תוית לכתובת הזאת כדי להכניס לפנקס הכתובות - + &Label: ת&וית: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - הכתובת אליה יישלח התשלום (למשל 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book בחר כתובת מפנקס הכתובות - + Alt+A Alt+A - + Paste address from clipboard הדבר כתובת מהלוח - + Alt+P Alt+P - + Remove this recipient הסר את המקבל הזה - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - הכנס כתובת ביטקוין (למשל 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + הכנס כתובת לייטקוין (למשל Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + חתימות - חתום או אמת הודעה + + + + &Sign Message + חתום על הו&דעה + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + אתה יכול לחתום על הודעות עם הכתובות שלך כדי להוכיח שהן בבעלותך. היזהר לא לחתום על משהו מעורפל, שכן התקפות פישינג עשויות לגרום לך בעורמה למסור את זהותך. חתום רק על אמרות מפורטות לחלוטין שאתה מסכים עימן. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + הכתובת איתה לחתום על ההודעה (למשל Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + בחר כתובת מפנקס הכתובות + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + הדבק כתובת מהלוח + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + הכנס כאן את ההודעה שעליך ברצונך לחתום + + + + Signature + חתימה + + + + Copy the current signature to the system clipboard + העתק את החתימה הנוכחית ללוח המערכת + + + + Sign the message to prove you own this CasinoCoin address + חתום על ההודעה כדי להוכיח שכתובת הלייטקוין הזו בבעלותך. + + + + Sign &Message + חתום על הודעה + + + + Reset all sign message fields + אפס את כל שדות החתימה על הודעה + + + + + Clear &All + נקה הכל + + + + &Verify Message + אמת הודעה + + + + Enter the signing 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. + הכנס למטה את הכתובת החותמת, ההודעה (ודא שאתה מעתיק מעברי שורה, רווחים, טאבים וכו' באופן מדויק) והחתימה כדי לאמת את ההודעה. היזהר לא לפרש את החתימה כיותר ממה שמופיע בהודעה החתומה בעצמה, כדי להימנע מליפול קורבן למתקפת איש-באמצע. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + הכתובת איתה ההודעה נחתמה (למשל Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + אמת את ההודעה כדי להבטיח שהיא נחתמה עם כתובת הלייטקוין הנתונה + + + + Verify &Message + אימות הודעה + + + + Reset all verify message fields + אפס את כל שדות אימות הודעה + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + הכנס כתובת לייטקוין (למשל Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + לחץ "חתום על ההודעה" כדי לחולל חתימה + + + + Enter CasinoCoin signature + הכנס חתימת לייטקוין + + + + + The entered address is invalid. + הכתובת שהוכנסה אינה תקינה. + + + + + + + Please check the address and try again. + אנא בדוק את הכתובת ונסה שנית. + + + + + The entered address does not refer to a key. + הכתובת שהוכנסה אינה מתייחסת למפתח. + + + + Wallet unlock was cancelled. + פתיחת הארנק בוטלה. + + + + Private key for the entered address is not available. + המפתח הפרטי עבור הכתובת שהוכנסה אינו זמין. + + + + Message signing failed. + החתימה על ההודעה נכשלה. + + + + Message signed. + ההודעה נחתמה. + + + + The signature could not be decoded. + לא ניתן לפענח את החתימה. + + + + + Please check the signature and try again. + אנא בדוק את החתימה ונסה שנית. + + + + The signature did not match the message digest. + החתימה לא תואמת את תקציר ההודעה. + + + + Message verification failed. + אימות ההודעה נכשל. + + + + Message verified. + ההודעה אומתה. + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [רשת-בדיקה] TransactionDesc - - Open for %1 blocks - פתוח למשך %1 בלוקים - - - + Open until %1 פתוח עד %1 - - %1/offline? - %1/לא מחובר? + + %1/offline + %1/מנותק - + %1/unconfirmed %1/ממתין לאישור - + %1 confirmations %1 אישורים - - <b>Status:</b> - <b>מצב:</b> + + Status + מצב + + + + , broadcast through %n node(s) + , הופץ דרך צומת אחד, הופץ דרך %n צמתים - + + Date + תאריך + + + + Source + מקור + + + + Generated + נוצר + + + + + From + מאת + + + + + + To + אל + + + + + own address + כתובת עצמית + + + + label + תוית + + + + + + + + Credit + זיכוי + + + + matures in %n more block(s) + מבשיל בעוד בלוק אחדמבשיל בעוד %n בלוקים + + + + not accepted + לא התקבל + + + + + + + Debit + חיוב + + + + Transaction fee + עמלת פעולה + + + + Net amount + כמות נקיה + + + + Message + הודעה + + + + Comment + הערה + + + + Transaction ID + זיהוי פעולה + + + + Generated coins must mature 120 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. + מטבעות שנוצרים חייבים להבשיל למשך 120 בלוקים לפני שניתן לנצל אותם. כשיצרת את הבלוק הזה, הוא הופץ לרשת כדי להתווסף לשרשרת הבלוקים. אם הוא אינו מצליח לביע לשרשרת, המצב שלו ישתנה ל"לא התקבל" ולא ניתן יהיה לנצל אותו. זה עשוי לקרות מעת לעת אם צומת אחר יוצר בלוק בטווח של מספר שניות מהבלוק שלך. + + + + Debug information + מידע ניפוי + + + + Transaction + פעולה + + + + Inputs + קלטים + + + + Amount + כמות + + + + true + אמת + + + + false + שקר + + + , has not been successfully broadcast yet , טרם שודר בהצלחה - - - , broadcast through %1 node - , שודר דרך צומת %1 + + + Open for %n more block(s) + פתח למשך בלוק %n יותרפתח למשך %n בלוקים נוספים - - , broadcast through %1 nodes - , שודר דרך %1 צמתים - - - - <b>Date:</b> - <b>תאריך:</b> - - - - <b>Source:</b> Generated<br> - <b>מקור:</b> נוצר<br> - - - - - <b>From:</b> - <b>מאת:</b> - - - + unknown לא ידוע - - - - - <b>To:</b> - <b>אל:</b> - - - - (yours, label: - (שלך, תוית: - - - - (yours) - (שלך) - - - - - - - <b>Credit:</b> - <b>זיכוי:</b> - - - - (%1 matures in %2 more blocks) - (%1 יבגור עוד %2 בלוקים) - - - - (not accepted) - (לא התקבל) - - - - - - <b>Debit:</b> - <b<חיוב:</b> - - - - <b>Transaction fee:</b> - <b>עמלת פעולה:</b> - - - - <b>Net amount:</b> - <b>כמות נטו:</b> - - - - Message: - הודעה: - - - - Comment: - הערה: - - - - Transaction ID: - מזהה פעולה: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - מטבעות שנוצרו חייבים לחכות 120 בלוקים לפני שניתן לנצל אותם. כשיצרת את הבלוק הזה, הוא שודר לרשת כדי להתווסף לשרשרת הבלוקים. אם הוא אינו מצליח להיכנס לשרשרת, הוא ישתנה ל"לא התקבל" ולא ניתן יהיה לנצל אותו. זה יכול לקרות מדי פעם אם צומת אחר מייצר בלוק בהפרש של מספר שניות מהבלוק שלך. - TransactionDescDialog - + Transaction details פרטי הפעולה - + This pane shows a detailed description of the transaction חלונית זו מציגה תיאור מפורט של הפעולה @@ -1574,117 +1847,117 @@ Address: %4 TransactionTableModel - + Date תאריך - + Type סוג - + Address כתובת - + Amount כמות - - Open for %n block(s) - פתוח למשך בלוק אחדפתוח למשך %n בלוקים + + Open for %n more block(s) + פתח למשך בלוק %n יותרפתח למשך %n בלוקים נוספים - + Open until %1 פתוח עד %1 - + Offline (%1 confirmations) לא מחובר (%1 אישורים) - + Unconfirmed (%1 of %2 confirmations) ממתין לאישור (%1 מתוך %2 אישורים) - + Confirmed (%1 confirmations) מאושר (%1 אישורים) - - Mined balance will be available in %n more blocks - יתרה שנכרתה תהיה זמינה עוד בלוק אחדיתרה שנכרתה תהיה זמינה עוד %n בלוקים + + Mined balance will be available when it matures in %n more block(s) + המאזן שנכרה יהיה זמין כשהוא מבשיל בעוד בלוק אחדהמאזן שנכרה יהיה זמין כשהוא מבשיל בעוד %n בלוקים - + This block was not received by any other nodes and will probably not be accepted! הבלוק הזה לא נקלט על ידי אף צומת אחר, וכנראה לא יתקבל! - + Generated but not accepted נוצר אך לא התקבל - + Received with התקבל עם - + Received from התקבל מאת - + Sent to נשלח ל - + Payment to yourself תשלום לעצמך - + Mined נכרה - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. מצב הפעולה. השהה את הסמן מעל שדה זה כדי לראות את מספר האישורים. - + Date and time that the transaction was received. התאריך והשעה בה הפעולה הזאת התקבלה. - + Type of transaction. סוג הפעולה. - + Destination address of transaction. כתובת היעד של הפעולה. - + Amount removed from or added to balance. הכמות שהתווספה או הוסרה מהיתרה. @@ -1692,815 +1965,967 @@ Address: %4 TransactionView - - + + All הכל - + Today היום - + This week השבוע - + This month החודש - + Last month החודש שעבר - + This year השנה - + Range... טווח... - + Received with התקבל עם - + Sent to נשלח ל - + To yourself לעצמך - + Mined נכרה - + Other אחר - + Enter address or label to search הכנס כתובת או תוית לחפש - + Min amount כמות מזערית - + Copy address העתק כתובת - + Copy label העתק תוית - + Copy amount העתק כמות - + + Copy transaction ID + העתק מזהה פעולה + + + Edit label ערוך תוית - + Show transaction details - + הצג פרטי פעולה - + Export Transaction Data יצוא נתוני פעולות - + Comma separated file (*.csv) קובץ מופרד בפסיקים (*.csv) - + Confirmed מאושר - + Date תאריך - + Type סוג - + Label תוית - + Address כתובת - + Amount כמות - + ID מזהה - + Error exporting שגיאה ביצוא - + Could not write to file %1. לא מסוגל לכתוב לקובץ %1. - + Range: טווח: - + to אל - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - העתק את הכתובת שסומנה ללוח המערכת - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - שולח... + + Send Coins + שלח מטבעות - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - מ&זער למגש במקום לשורת המשימות + + Export the data in the current tab to a file + יצוא הנתונים בטאב הנוכחי לקובץ - - Show only a tray icon after minimizing the window - הצג אייקון מגש בלבד לאחר מזעור החלון + + Backup Wallet + גבה ארנק - - M&inimize on close - + + Wallet Data (*.dat) + נתוני ארנק (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - מזער את התוכנה במקום לצאת ממנה כשהחלון נסגר. כשאפשרות זו פעילה, התוכנה תיסגר רק לאחר בחירת יציאה מהתפריט. + + Backup Failed + גיבוי נכשל + + + + There was an error trying to save the wallet data to the new location. + הייתה שגיאה בנסיון לשמור את המידע הארנק למיקום החדש. + + + + Backup Successful + גיבוי הושלם בהצלחה + + + + The wallet data was successfully saved to the new location. + נתוני הארנק נשמרו בהצלחה במקום החדש. bitcoin-core - - Bitcoin version - גרסת ביטקוין + + CasinoCoin version + גרסת לייטקוין - + Usage: שימוש: - - Send command to -server or bitcoind - שלח פקודה ל -server או bitcoind + + Send command to -server or casinocoind + שלח פקודה ל -server או casinocoind - + List commands רשימת פקודות - + Get help for a command קבל עזרה עבור פקודה - + Options: אפשרויות: - - Specify configuration file (default: bitcoin.conf) - ציין קובץ הגדרות (ברירת מחדל: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + ציין קובץ הגדרות (ברירת מחדל: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - ציין קובץ pid (ברירת מחדל: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + ציין קובץ pid (ברירת מחדל: casinocoind.pid) - - Generate coins - צור מטבעות - - - - Don't generate coins - אל תייצר מטבעות - - - + Specify data directory ציין תיקיית נתונים - + Set database cache size in megabytes (default: 25) קבע את גודל המטמון של מסד הנתונים במגהבייט (ברירת מחדל: 25) - - Set database disk log size in megabytes (default: 100) - קבע את גודל יומן פעילות מסד הנתונים במגהבייט (ברירת מחדל: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + האזן לחיבורים ב<פורט> (ברירת מחדל: 47950 או ברשת הבדיקה: 17950) - - Specify connection timeout (in milliseconds) - ציין הגבלת זמן לחיבור (במילישניות) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - האזן לחיבורים ב<פורט> (ברירת מחדל: 8333 או ברשת הבדיקה: 18333) - - - + Maintain at most <n> connections to peers (default: 125) החזק לכל היותר <n> חיבורים לעמיתים (ברירת מחדל: 125) - - Connect only to the specified node - התחבר רק לצומת המצוין - - - + Connect to a node to retrieve peer addresses, and disconnect - + התחבר לצומת כדי לדלות כתובות עמיתים, ואז התנתק - + Specify your own public address - + ציין את הכתובת הפומבית שלך - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) סף להתנתקות מעמיתים הנוהגים שלא כהלכה (ברירת מחדל: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) מספר שניות למנוע מעמיתים הנוהגים שלא כהלכה מלהתחבר מחדש (ברירת מחדל: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - חוצץ מירבי לקבלה לכל חיבור, <n>*1000 בתים (ברירת מחדל: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + אירעה שגיאה בעת הגדרת פורט RPC %u להאזנה ב-IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - חוצץ מירבי לשליחה לכל חיבור, <n>*1000 בתים (ברירת מחדל: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + האזן לחיבורי JSON-RPC ב- <port> (ברירת מחדל: 47970 או רשת בדיקה: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands קבל פקודות משורת הפקודה ו- JSON-RPC - + Run in the background as a daemon and accept commands רוץ ברקע כדימון וקבל פקודות - + Use the test network השתמש ברשת הבדיקה - - Output extra debugging information - פלוט מידע דיבאג נוסף + + Accept connections from outside (default: 1 if no -proxy or -connect) + קבל חיבורים מבחוץ (ברירת מחדל: 1 ללא -proxy או -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, עליך לקבוע סיסמת RPC בקובץ הקונפיגורציה: + %s +מומלץ להשתמש בסיסמא האקראית הבאה: +rpcuser=casinocoinrpc +rpcpassword=%s +(אין צורך לזכור את הסיסמה) +אסור ששם המשתמש והסיסמא יהיו זהים. +אם הקובץ אינו קיים, צור אותו עם הרשאות קריאה לבעלים בלבד. +זה מומלץ לסמן alertnotify כדי לקבל דיווח על תקלות; +למשל: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + אירעה שגיאה בעת הגדרת פורט RPC %u להאזנה ב-IPv6, נסוג ל-IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + קשור עם כתובת נתונה והאזן לה תמיד. השתמש בסימון [host]:port עבוד IPv6. + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + לא מסוגל להשיג נעילה על תיקיית הנתונים %s. כנראה שלייטקוין כבר רץ. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + שגיאה: הפעולה נדחתה! זה עלול לקרות אם כמה מהמטבעות בארנק שלך כבר נוצלו, למשל אם השתמשת בעותק של wallet.dat ומטבעות נשלחו בעותק אך לא סומנו כמנוצלות כאן. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + שגיאה: הפעולה הזאת דורשת עמלת פעולה של לפחות %s עקב הכמות, המורכבות, או השימוש בכספים שהתקבלו לאחרונה! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + בצע פעולה כאשר ההודעה הרלוונטית מתקבלת(%s בשורת הפקודה משתנה על-ידי ההודעה) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + בצע פקודה כאשר פעולת ארנק משתנה (%s ב cmd יוחלף ב TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + קבע גודל מקסימלי עבור פעולות עדיפות גבוהה/עמלה נמוכה בבתים (ברירת מחדל: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + זוהי בניית ניסיון טרום-שחרור - השימוש בה על אחריותך - אין להשתמש לצורך כריה או יישומי מסחר + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + אזהרה: -paytxfee נקבע לערך מאד גבוה! זוהי עמלת הפעולה שתשלם אם אתה שולח פעולה. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + אזהרה: הפעולות המוצגות עשויות לא להיות נכונות! ייתכן ואתה צריך לשדרג, או שצמתים אחרים צריכים לשדרג. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + אזהרה: אנא בדוק שהתאריך והשעה של המחשב שלך נכונים! אם השעון שלך אינו נכון לייטקוין לא יעבוד כראוי. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + אזהרה: שגיאה בקריאת wallet.dat! כל המתפחות נקראו באופן תקין, אך נתוני הפעולות או ספר הכתובות עלולים להיות חסרים או שגויים. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + אזהרה: קובץ wallet.dat מושחת, המידע חולץ! קובץ wallet.dat המקורח נשמר כ - wallet.{timestamp}.bak ב - %s; אם המאזן או הפעולות שגויים עליך לשחזר גיבוי. + + + + Attempt to recover private keys from a corrupt wallet.dat + נסה לשחזר מפתחות פרטיים מקובץ wallet.dat מושחת. + + + + Block creation options: + אפשרויות יצירת בלוק: + + + + Connect only to the specified node(s) + התחבר רק לצמתים המצוינים + + + + Corrupted block database detected + התגלה מסד נתוני בלוקים לא תקין + + + + Discover own IP address (default: 1 when listening and no -externalip) + גלה את כתובת ה-IP העצמית (ברירת מחדל: 1 כשמאזינים וללא -externalip) + + + + Do you want to rebuild the block database now? + האם תרצה כעט לבנות מחדש את מסד נתוני הבלוקים? + + + + Error initializing block database + שגיאה באתחול מסד נתוני הבלוקים + + + + Error initializing wallet database environment %s! + שגיאה באתחול סביבת מסד נתוני הארנקים %s! + + + + Error loading block database + שגיאה בטעינת מסד נתוני הבלוקים + + + + Error opening block database + שגיאה בטעינת מסד נתוני הבלוקים + + + + Error: Disk space is low! + שגיאה: מעט מקום פנוי בדיסק! + + + + Error: Wallet locked, unable to create transaction! + שגיאה: הארנק נעול, אין אפשרות ליצור פעולה! + + + + Error: system error: + שגיאה: שגיאת מערכת: + + + + Failed to listen on any port. Use -listen=0 if you want this. + האזנה נכשלה בכל פורט. השתמש ב- -listen=0 אם ברצונך בכך. + + + + Failed to read block info + קריאת מידע הבלוקים נכשלה + + + + Failed to read block + קריאת הבלוק נכשלה + + + + Failed to sync block index + סנכרון אינדקס הבלוקים נכשל + + + + Failed to write block index + כתיבת אינדקס הבלוקים נכשל + + + + Failed to write block info + כתיבת מידע הבלוקים נכשל + + + + Failed to write block + כתיבת הבלוק נכשלה + + + + Failed to write file info + כתיבת מידע הקבצים נכשלה + + + + Failed to write to coin database + כתיבת מסד נתוני המטבעות נכשלה + + + + Failed to write transaction index + כתיבת אינדקס הפעולות נכשלה + + + + Failed to write undo data + כתיבת נתוני ביטול נכשלה + + + + Find peers using DNS lookup (default: 1 unless -connect) + מצא עמיתים ע"י חיפוש DNS (ברירת מחדל: 1 ללא -connect) + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + מספר הבלוקים לבדוק בעת אתחול (ברירת מחדל: 288, 0 = כולם) + + + + How thorough the block verification is (0-4, default: 3) + מידת היסודיות של אימות הבלוקים (0-4, ברירת מחדל: 3) + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + בנה מחדש את אינדק שרשרת הבלוקים מקבצי ה-blk000??.dat הנוכחיים. + + + + Set the number of threads to service RPC calls (default: 4) + קבע את מספר תהליכוני לשירות קריאות RPC (ברירת מחדל: 4) + + + + Verifying blocks... + מאמת את שלמות מסד הנתונים... + + + + Verifying wallet... + מאמת את יושרת הארנק... + + + + Imports blocks from external blk000??.dat file + מייבא בלוקים מקובצי blk000??.dat חיצוניים + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + מידע + + + + Invalid -tor address: '%s' + כתובת לא תקינה ל -tor: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + תחזק אינדקס פעולות מלא (ברירת מחדל: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + חוצץ קבלה מירבי לכל חיבור, <n>*1000 בתים (ברירת מחדל: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + חוצץ שליחה מירבי לכל חיבור, <n>*1000 בתים (ברירת מחדל: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + קבל רק שרשרת בלוקים התואמת נקודות ביקורת מובנות (ברירת מחדל: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + התחבר רק לצמתים ברשת <net> (IPv4, IPv6 או Tor) + + + + Output extra debugging information. Implies all other -debug* options + פלוט מידע ניפוי נוסף. נובע מכך כל אפשרויות -debug* האחרות. + + + + Output extra network debugging information + פלוט מידע נוסף לניפוי שגיאות ברשת. + + + Prepend debug output with timestamp הוסף חותמת זמן לפני פלט דיבאג - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + אפשרויות SSL: (ראה את הויקי של לייטקוין עבור הוראות הגדרת SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + בחר את גרסת פרוקסי SOCKS להשתמש בה (4-5, ברירת מחדל: 5) + + + Send trace/debug info to console instead of debug.log file שלח מידע דיבאג ועקבה לקונסולה במקום לקובץ debug.log - + Send trace/debug info to debugger שלח מידע דיבאג ועקבה לכלי דיבאג - + + Set maximum block size in bytes (default: 250000) + קבע את גדול הבלוק המירבי בבתים (ברירת מחדל: 250000) + + + + Set minimum block size in bytes (default: 0) + קבע את גודל הבלוק המינימלי בבתים (ברירת מחדל: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + כווץ את קובץ debug.log בהפעלת הקליינט (ברירת מחדל: 1 ללא -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + ציין הגבלת זמן לחיבור במילישניות (ברירת מחדל: 5000) + + + + System error: + שגיאת מערכת: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + השתמש ב-UPnP כדי למפות את הפורט להאזנה (ברירת מחדל: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + השתמש ב-UPnP כדי למפות את הפורט להאזנה (ברירת מחדל: 1 בעת האזנה) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + השתמש בפרוקסי כדי להגיע לשירותים חבויים ב-tor (ברירת מחדל: כמו ב- -proxy) + + + Username for JSON-RPC connections שם משתמש לחיבורי JSON-RPC - + + Warning + אזהרה + + + + Warning: This version is obsolete, upgrade required! + אזהרה: הגרסה הזאת מיושנת, יש צורך בשדרוג! + + + + You need to rebuild the databases using -reindex to change -txindex + עליך לבנות מחדש את מסדי הנתונים תוך שימוש ב- -reindex על מנת לשנות את -txindex + + + + wallet.dat corrupt, salvage failed + קובץ wallet.dat מושחת, החילוץ נכשל + + + Password for JSON-RPC connections סיסמה לחיבורי JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - האזן לחיבורי JSON-RPC ב<פורט> (ברירת מחדל: 8332) - - - + Allow JSON-RPC connections from specified IP address אפשר חיבורי JSON-RPC מכתובת האינטרנט המצוינת - + Send commands to node running on <ip> (default: 127.0.0.1) שלח פקודות לצומת ב-<ip> (ברירת מחדל: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) בצע פקודה זו כשהבלוק הטוב ביותר משתנה (%s בפקודה יוחלף בגיבוב הבלוק) - + Upgrade wallet to latest format שדרג את הארנק לפורמט העדכני - + Set key pool size to <n> (default: 100) קבע את גודל המאגר ל -<n> (ברירת מחדל: 100) - + Rescan the block chain for missing wallet transactions סרוק מחדש את שרשרת הבלוקים למציאת פעולות חסרות בארנק - - How many blocks to check at startup (default: 2500, 0 = all) - מספר הבלוקים לבדוק בעת ההפעלה (ברירת מחדל: 2500, 0=כולם) - - - - How thorough the block verification is (0-6, default: 1) - מידת היסודיות של אימות הבלוקים (0-6, ברירת מחדל: 1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - אפשרויות SSL: (ראה את הויקי של ביטקוין עבור הוראות להתקנת SSL) - - - + Use OpenSSL (https) for JSON-RPC connections השתמש ב-OpenSSL (https( עבור חיבורי JSON-RPC - + Server certificate file (default: server.cert) קובץ תעודת שרת (ברירת מחדל: server.cert) - + Server private key (default: server.pem) מפתח פרטי של השרת (ברירת מחדל: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) צפנים קבילים (ברירת מחדל: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message הודעת העזרה הזו - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - אינו מסוגל לנעול את תיקיית הנתונים %s. כנראה שביטקוין כבר רץ. - - - - Bitcoin - ביטקוין - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + לא מסוגל לקשור ל-%s במחשב זה (הקשירה החזירה שגיאה %d, %s) - + Connect through socks proxy - + התחבר דרך פרוקסי SOCKS - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + אפשר בדיקת DNS עבור -addnode, -seednode ו- -connect - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... טוען כתובות... - - Error loading blkindex.dat - שגיאה בטעינת הקובץ blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted שגיאה בטעינת הקובץ wallet.dat: הארנק מושחת - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - שגיאה בטעינת הקובץ wallet.dat: הארנק דורש גרסה חדשה יותר של ביטקוין + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + שגיאה בטעינת הקובץ wallet.dat: הארנק דורש גרסה חדשה יותר של לייטקוין - - Wallet needed to be rewritten: restart Bitcoin to complete - יש לכתוב מחדש את הארנק: אתחל את ביטקוין לסיום + + Wallet needed to be rewritten: restart CasinoCoin to complete + יש לכתוב מחדש את הארנק: אתחל את לייטקוין לסיום - + Error loading wallet.dat שגיאה בטעינת הקובץ wallet.dat - + Invalid -proxy address: '%s' - + כתובת -proxy לא תקינה: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + רשת לא ידועה צוינה ב- -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + התבקשה גרסת פרוקסי -socks לא ידועה: %i - + Cannot resolve -bind address: '%s' - + לא מסוגל לפתור כתובת -bind: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + לא מסוגל לפתור כתובת -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + כמות לא תקינה עבור -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - שגיאה: הארנק נעול, לא ניתן ליצור פעולה - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - שגיאה: הפעולה דורשת עמלת פעולה של לפחות %s מפאת הכמות, המורכבות, או השימוש בכספים שהתקבלו לאחרונה - - - - Error: Transaction creation failed - שגיאה: יצירת הפעולה נכשלה - - - - Sending... - שולח... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - שגיאה: הפעולה נדחתה. זה עשוי לקרות אם חלק מהמטבעות בארנק שלך כבר נוצלו, למשל אם השתמשת בעותק של הקובץ wallet.dat ומטבעות נוצלו בהעתק אך לא סומנו כמנוצלות כאן. - - - + Invalid amount כמות לא תקינה - + Insufficient funds אין מספיק כספים - + Loading block index... טוען את אינדקס הבלוקים... - + Add a node to connect to and attempt to keep the connection open הוסף צומת להתחברות ונסה לשמור את החיבור פתוח - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + לא ניתן לקשור ל-%s במחשב זה. לייטקוין כנראה עדיין רץ. - - Find peers using internet relay chat (default: 0) - מצא עמיתים תוך שימוש ב-IRC (ברירת מחדל: 0) - - - - Accept connections from outside (default: 1) - קבל חיבורים מבחוץ (ברירת מחדל: 1) - - - - Find peers using DNS lookup (default: 1) - מצא עמיתים באמצעות בדיקת DNS (ברירת מחדל: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - השתמש ב-UPnP כדי למפות את הפורט להאזנה (ברירת מחדל: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - השתמש ב-UPnP כדי למפות את הפורט להאזנה (ברירת מחדל: 0) - - - + Fee per KB to add to transactions you send עמלה להוסיף לפעולות שאתה שולח עבור כל KB - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... טוען ארנק... - + Cannot downgrade wallet לא יכול להוריד דרגת הארנק - - Cannot initialize keypool - לא יכול לאתחל את מאגר המפתחות - - - + Cannot write default address לא יכול לכתוב את כתובת ברירת המחדל - + Rescanning... סורק מחדש... - + Done loading טעינה הושלמה - + To use the %s option להשתמש באפשרות %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, עליך לקבוע את rpcpassword בקובץ ההגדרות: -%s -מומלץ להשתמש בסיסמה האקראית הבאה: -rpcuser=bitcoinrpc -rpcpassword=%s -(אין צורך לזכור סיסמה זו) -אם הקובץ אינו קיים, צור אותו עם הרשאות קריאה לבעלים בלבד. - - - + Error שגיאה - - An error occured while setting up the RPC port %i for listening: %s - אירעה שגיאה בעת קביעת פורט RPC %i להאזנה: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2508,10 +2933,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s אם הקובץ אינו קיים, צור אותו עם הרשאות קריאה לבעלים בלבד. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - אזהרה: אנא בדוק שהתאריך והשעה של המחשב הזה נכונים. אם השעון שלך שגוי ביטקוין לא יפעל כהלכה. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts new file mode 100644 index 0000000..e063f4c --- /dev/null +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -0,0 +1,2922 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + बिटकोइन के संबंध में + + + + <b>CasinoCoin</b> version + बिटकोइन वर्सन + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + कापीराइट + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + पता पुस्तक + + + + Double-click to edit address or label + दो बार क्लिक करे पता या लेबल संपादन करने के लिए ! + + + + Create a new address + नया पता लिखिए ! + + + + Copy the currently selected address to the system clipboard + चुनिन्दा पते को सिस्टम क्लिपबोर्ड पर कापी करे ! + + + + &New Address + &नया पता + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + &पता कॉपी करे + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + &मिटाए !! + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + &लेबल कॉपी करे + + + + &Edit + &एडिट + + + + Send &Coins + + + + + Export Address Book Data + पता पुस्तक का डेटा एक्सपोर्ट (निर्यात) करे ! + + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + + Error exporting + ग़लतियाँ एक्सपोर्ट (निर्यात) करे! + + + + Could not write to file %1. + फाइल में लिख नही सके %1. + + + + AddressTableModel + + + Label + लेबल + + + + Address + पता + + + + (no label) + (कोई लेबल नही !) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + पहचान शब्द/अक्षर डालिए ! + + + + New passphrase + नया पहचान शब्द/अक्षर डालिए ! + + + + Repeat new passphrase + दोबारा नया पहचान शब्द/अक्षर डालिए ! + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + नया पहचान शब्द/अक्षर वॉलेट मे डालिए ! <br/> कृपा करके पहचान शब्द में <br> 10 से ज़्यादा अक्षॉरों का इस्तेमाल करे </b>,या <b>आठ या उससे से ज़्यादा शब्दो का इस्तेमाल करे</b> ! + + + + Encrypt wallet + एनक्रिप्ट वॉलेट ! + + + + This operation needs your wallet passphrase to unlock the wallet. + वॉलेट खोलने के आपका वॉलेट पहचान शब्द्‌/अक्षर चाईए ! + + + + Unlock wallet + वॉलेट खोलिए + + + + This operation needs your wallet passphrase to decrypt the wallet. + वॉलेट डीक्रिप्ट( विकोड) करने के लिए आपका वॉलेट पहचान शब्द्‌/अक्षर चाईए ! + + + + Decrypt wallet + डीक्रिप्ट वॉलेट + + + + Change passphrase + पहचान शब्द/अक्षर बदलिये ! + + + + Enter the old and new passphrase to the wallet. + कृपा करके पुराना एवं नया पहचान शब्द/अक्षर वॉलेट में डालिए ! + + + + Confirm wallet encryption + वॉलेट एनक्रिपशन को प्रमाणित कीजिए ! + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + वॉलेट एनक्रिप्ट हो गया ! + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + वॉलेट एनक्रिप्ट नही हुआ! + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + वॉलेट एनक्रिपशन नाकाम हो गया इंटर्नल एरर की वजह से! आपका वॉलेट एनक्रीपत नही हुआ है! + + + + + The supplied passphrases do not match. + आपके द्वारा डाले गये पहचान शब्द/अक्षर मिलते नही है ! + + + + Wallet unlock failed + वॉलेट का लॉक नही खुला ! + + + + + + The passphrase entered for the wallet decryption was incorrect. + वॉलेट डीक्रिप्ट करने के लिए जो पहचान शब्द/अक्षर डाले गये है वो सही नही है! + + + + Wallet decryption failed + वॉलेट का डीक्रिप्ट-ष्ण असफल ! + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + नेटवर्क से समकालिक (मिल) रहा है ... + + + + &Overview + &विवरण + + + + Show general overview of wallet + वॉलेट का सामानया विवरण दिखाए ! + + + + &Transactions + & लेन-देन + + + + + Browse transaction history + देखिए पुराने लेन-देन के विवरण ! + + + + Edit the list of stored addresses and labels + स्टोर किए हुए पते और लेबलओ को बदलिए ! + + + + Show the list of addresses for receiving payments + पते की सूची दिखाए जिन्हे भुगतान करना है ! + + + + E&xit + बाहर जायें + + + + Quit application + अप्लिकेशन से बाहर निकलना ! + + + + Show information about CasinoCoin + बीटकोइन के बारे में जानकारी ! + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + &विकल्प + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + &बैकप वॉलेट + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + पहचान शब्द/अक्षर जो वॉलेट एनक्रिपशन के लिए इस्तेमाल किया है उसे बदलिए! + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + बीटकोइन + + + + Wallet + वॉलेट + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + &फाइल + + + + &Settings + &सेट्टिंग्स + + + + &Help + &मदद + + + + Tabs toolbar + टैबस टूलबार + + + + + [testnet] + [टेस्टनेट] + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + %n सक्रिया संपर्क बीटकोइन नेटवर्क से%n सक्रिया संपर्क बीटकोइन नेटवर्क से + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + %n घंटा%n घंटे + + + + %n day(s) + %n दिन%n दिनो + + + + %n week(s) + %n हफ़्ता%n हफ्ते + + + + %1 behind + %1 पीछे + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + भूल + + + + Warning + चेतावनी + + + + Information + जानकारी + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + नवीनतम + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + भेजी ट्रांजक्शन + + + + Incoming transaction + प्राप्त हुई ट्रांजक्शन + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + तारीख: %1\n +राशि: %2\n +टाइप: %3\n +पता:%4\n + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + वॉलेट एन्क्रिप्टेड है तथा अभी लॉक्ड नहीं है + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + वॉलेट एन्क्रिप्टेड है तथा अभी लॉक्ड है + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + पता एडिट करना + + + + &Label + &लेबल + + + + The label associated with this address book entry + इस एड्रेस बुक से जुड़ा एड्रेस + + + + &Address + &पता + + + + The address associated with this address book entry. This can only be modified for sending addresses. + इस एड्रेस बुक से जुड़ी प्रविष्टि केवल भेजने वाले addresses के लिए बदली जा सकती है| + + + + New receiving address + नया स्वीकार्य पता + + + + New sending address + नया भेजने वाला पता + + + + Edit receiving address + एडिट स्वीकार्य पता + + + + Edit sending address + एडिट भेजने वाला पता + + + + The entered address "%1" is already in the address book. + डाला गया पता "%1" एड्रेस बुक में पहले से ही मोजूद है| + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + वॉलेट को unlock नहीं किया जा सकता| + + + + New key generation failed. + नयी कुंजी का निर्माण असफल रहा| + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + बीटकोइन-Qt + + + + version + संस्करण + + + + Usage: + खपत : + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + विकल्प + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + &ओके + + + + &Cancel + &कैन्सल + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + चेतावनी + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + फार्म + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + बाकी रकम : + + + + Unconfirmed: + अपुष्ट : + + + + Wallet + वॉलेट + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + <b>हाल का लेन-देन</b> + + + + Your current balance + आपका चालू बॅलेन्स + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + लेन देन की पुष्टि अभी नहीं हुई है, इसलिए इन्हें अभी मोजुदा बैलेंस में गिना नहीं गया है| + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + भुगतान का अनुरोध + + + + Amount: + राशि : + + + + Label: + लेबल : + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + लागू नही + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + सिक्के भेजें| + + + + Send to multiple recipients at once + एक साथ कई प्राप्तकर्ताओं को भेजें + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + बाकी रकम : + + + + 123.456 BTC + 123.456 BTC + + + + Confirm the send action + भेजने की पुष्टि करें + + + + S&end + + + + + <b>%1</b> to %2 (%3) + <b>%1</b> से %2 (%3) + + + + Confirm send coins + सिक्के भेजने की पुष्टि करें + + + + Are you sure you want to send %1? + क्या आप %1 भेजना चाहते हैं? + + + + and + और + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + भेजा गया अमाउंट शुन्य से अधिक होना चाहिए| + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + फार्म + + + + A&mount: + अमाउंट: + + + + Pay &To: + प्राप्तकर्ता: + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + आपकी एड्रेस बुक में इस एड्रेस के लिए एक लेबल लिखें + + + + &Label: + लेबल: + + + + Choose address from address book + + + + + Alt+A + Alt-A + + + + Paste address from clipboard + Clipboard से एड्रेस paste करें + + + + Alt+P + Alt-P + + + + Remove this recipient + प्राप्तकर्ता हटायें + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin एड्रेस लिखें (उदाहरण: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + Alt-A + + + + Paste address from clipboard + Clipboard से एड्रेस paste करें + + + + Alt+P + Alt-P + + + + Enter the message you want to sign here + + + + + Signature + हस्ताक्षर + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin एड्रेस लिखें (उदाहरण: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + खुला है जबतक %1 + + + + %1/offline + + + + + %1/unconfirmed + %1/अपुष्ट + + + + %1 confirmations + %1 पुष्टियाँ + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + taareek + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + राशि + + + + true + सही + + + + false + ग़लत + + + + , has not been successfully broadcast yet + , अभी तक सफलतापूर्वक प्रसारित नहीं किया गया है + + + + Open for %n more block(s) + + + + + unknown + अज्ञात + + + + TransactionDescDialog + + + Transaction details + लेन-देन का विवरण + + + + This pane shows a detailed description of the transaction + ये खिड़की आपको लेन-देन का विस्तृत विवरण देगी ! + + + + TransactionTableModel + + + Date + taareek + + + + Type + टाइप + + + + Address + पता + + + + Amount + राशि + + + + Open for %n more block(s) + + + + + Open until %1 + खुला है जबतक %1 + + + + Offline (%1 confirmations) + ऑफलाइन ( %1 पक्का करना) + + + + Unconfirmed (%1 of %2 confirmations) + अपुष्ट ( %1 मे %2 पक्के ) + + + + Confirmed (%1 confirmations) + पक्के ( %1 पक्का करना) + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + यह ब्लॉक किसी भी और नोड को मिला नही है ! शायद यह ब्लॉक कोई भी नोड स्वीकारे गा नही ! + + + + Generated but not accepted + जेनरेट किया गया किंतु स्वीकारा नही गया ! + + + + Received with + स्वीकारा गया + + + + Received from + स्वीकार्य ओर से + + + + Sent to + भेजा गया + + + + Payment to yourself + भेजा खुद को भुगतान + + + + Mined + माइंड + + + + (n/a) + (लागू नहीं) + + + + Transaction status. Hover over this field to show number of confirmations. + ट्रांसेक्शन स्तिथि| पुष्टियों की संख्या जानने के लिए इस जगह पर माउस लायें| + + + + Date and time that the transaction was received. + तारीख तथा समय जब ये ट्रांसेक्शन प्राप्त हुई थी| + + + + Type of transaction. + ट्रांसेक्शन का प्रकार| + + + + Destination address of transaction. + ट्रांसेक्शन की मंजिल का पता| + + + + Amount removed from or added to balance. + अमाउंट बैलेंस से निकला या जमा किया गया | + + + + TransactionView + + + + All + सभी + + + + Today + आज + + + + This week + इस हफ्ते + + + + This month + इस महीने + + + + Last month + पिछले महीने + + + + This year + इस साल + + + + Range... + विस्तार... + + + + Received with + स्वीकार करना + + + + Sent to + भेजा गया + + + + To yourself + अपनेआप को + + + + Mined + माइंड + + + + Other + अन्य + + + + Enter address or label to search + ढूँदने के लिए कृपा करके पता या लेबल टाइप करे ! + + + + Min amount + लघुत्तम राशि + + + + Copy address + पता कॉपी करे + + + + Copy label + लेबल कॉपी करे + + + + Copy amount + कॉपी राशि + + + + Copy transaction ID + + + + + Edit label + एडिट लेबल + + + + Show transaction details + + + + + Export Transaction Data + लेन-देन का डेटा निर्यात करे ! + + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + + Confirmed + पक्का + + + + Date + taareek + + + + Type + टाइप + + + + Label + लेबल + + + + Address + पता + + + + Amount + राशि + + + + ID + ID + + + + Error exporting + ग़लतियाँ एक्सपोर्ट (निर्यात) करे! + + + + Could not write to file %1. + फाइल में लिख नही सके %1. + + + + Range: + विस्तार: + + + + to + तक + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + बैकप वॉलेट + + + + Wallet Data (*.dat) + वॉलेट डेटा (*.dat) + + + + Backup Failed + बैकप असफल + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + बैकप सफल + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + बीटकोइन संस्करण + + + + Usage: + खपत : + + + + Send command to -server or casinocoind + -server या casinocoind को कमांड भेजें + + + + List commands + commands की लिस्ट बनाएं + + + + Get help for a command + किसी command के लिए मदद लें + + + + Options: + विकल्प: + + + + Specify configuration file (default: casinocoin.conf) + configuraion की फाइल का विवरण दें (default: casinocoin.conf) + + + + Specify pid file (default: casinocoind.pid) + pid फाइल का विवरण दें (default: casinocoin.pid) + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + ब्लॉक्स जाँचे जा रहा है... + + + + Verifying wallet... + वॉलेट जाँचा जा रहा है... + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + जानकारी + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + चेतावनी + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + पता पुस्तक आ रही है... + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + राशि ग़लत है + + + + Insufficient funds + + + + + Loading block index... + ब्लॉक इंडेक्स आ रहा है... + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + वॉलेट आ रहा है... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + रि-स्केनी-इंग... + + + + Done loading + लोड हो गया| + + + + To use the %s option + + + + + Error + भूल + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index 300bbd6..7893bd9 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -3,122 +3,155 @@ AboutDialog - - About Bitcoin - O Bitcoinu + + About CasinoCoin + O CasinoCoin-u - - <b>Bitcoin</b> version - <b>Bitcoin</b> verzija + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> verzija - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Developers - -Ovo je eksperimentalan softver. - -Djeljen pod MIT/X11 licencom, pogledajte prateću datoteku license.txt ili http://www.opensource.org/licenses/mit-license.php. - -Ovaj proizvod sadrži softver kojeg je razvio OpenSSL Project za korištenje u OpenSSL Toolkit (http://www.openssl.org/) i kriptografski softver kojeg je napisao Eric Young (eay@cryptsoft.com) i UPnP softver kojeg je napisao Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + AddressBookPage - + Address Book Adresar - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Ovo su vaše Bitcoin adrese za primanje isplate. Možda želite dati drukčiju adresu svakom primatelju tako da možete pratiti tko je platio. - - - + Double-click to edit address or label Dvostruki klik za uređivanje adrese ili oznake - + Create a new address Dodajte novu adresu - + Copy the currently selected address to the system clipboard Kopiraj trenutno odabranu adresu u međuspremnik - + &New Address - + &Nova adresa - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Ovo su vaše CasinoCoin adrese za primanje isplate. Možda želite dati drukčiju adresu svakom primatelju tako da možete pratiti tko je platio. + + + &Copy Address - + &Kopirati adresu - + Show &QR Code Prikaži &QR Kôd - - Sign a message to prove you own this address - Potpišite poruku kako bi dokazali da posjedujete ovu adresu + + Sign a message to prove you own a CasinoCoin address + - - &Sign Message - &Potpišite poruku + + Sign &Message + - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Brisanje trenutno odabrane adrese s popisa. Samo adrese za slanje se mogu izbrisati. + + Delete the currently selected address from the list + - + + Export the data in the current tab to a file + Izvoz podataka iz trenutnog taba u datoteku + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete &Brisanje - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Kopirati &oznaku - + &Edit + &Izmjeniti + + + + Send &Coins - + Export Address Book Data Izvoz podataka adresara - + Comma separated file (*.csv) Datoteka vrijednosti odvojenih zarezom (*. csv) - + Error exporting Pogreška kod izvoza - + Could not write to file %1. Ne mogu pisati u datoteku %1. @@ -126,17 +159,17 @@ Ovaj proizvod sadrži softver kojeg je razvio OpenSSL Project za korištenje u AddressTableModel - + Label Oznaka - + Address Adresa - + (no label) (bez oznake) @@ -144,432 +177,460 @@ Ovaj proizvod sadrži softver kojeg je razvio OpenSSL Project za korištenje u AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase Unesite lozinku - + New passphrase Nova lozinka - + Repeat new passphrase Ponovite novu lozinku - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Unesite novi lozinku za novčanik. <br/> Molimo Vas da koristite zaporku od <b>10 ili više slučajnih znakova,</b> ili <b>osam ili više riječi.</b> - + Encrypt wallet Šifriranje novčanika - + This operation needs your wallet passphrase to unlock the wallet. Ova operacija treba lozinku vašeg novčanika kako bi se novčanik otključao. - + Unlock wallet Otključaj novčanik - + This operation needs your wallet passphrase to decrypt the wallet. Ova operacija treba lozinku vašeg novčanika kako bi se novčanik dešifrirao. - + Decrypt wallet Dešifriranje novčanika. - + Change passphrase Promjena lozinke - + Enter the old and new passphrase to the wallet. Unesite staru i novu lozinku za novčanik. - + Confirm wallet encryption Potvrdi šifriranje novčanika - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - UPOZORENJE: Ako šifrirate vaš novčanik i izgubite lozinku, <b>IZGUBIT ĆETE SVE SVOJE BITCOINSE!</b> -Jeste li sigurni da želite šifrirati svoj novčanik? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Upozorenje: Ako šifrirate vaš novčanik i izgubite lozinku, <b>IZGUBIT ĆETE SVE SVOJE CASINOCOINSE!</b> - - + + Are you sure you wish to encrypt your wallet? + Jeste li sigurni da želite šifrirati svoj novčanik? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted Novčanik šifriran - - Bitcoin 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. - Bitcoin će se sada zatvoriti kako bi dovršio postupak šifriranja. Zapamtite da šifriranje vašeg novčanika ne može u potpunosti zaštititi vaše bitcoine od krađe preko zloćudnog softvera koji bi bio na vašem računalu. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin će se sada zatvoriti kako bi dovršio postupak šifriranja. Zapamtite da šifriranje vašeg novčanika ne može u potpunosti zaštititi vaše casinocoine od krađe preko zloćudnog softvera koji bi bio na vašem računalu. - - - Warning: The Caps Lock key is on. - Upozorenje: Tipka Caps Lock je upaljena. - - - - - - + + + + Wallet encryption failed Šifriranje novčanika nije uspjelo - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Šifriranje novčanika nije uspjelo zbog interne pogreške. Vaš novčanik nije šifriran. - - + + The supplied passphrases do not match. Priložene lozinke se ne podudaraju. - + Wallet unlock failed Otključavanje novčanika nije uspjelo - - - + + + The passphrase entered for the wallet decryption was incorrect. Lozinka za dešifriranje novčanika nije točna. - + Wallet decryption failed Dešifriranje novčanika nije uspjelo - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Lozinka novčanika je uspješno promijenjena. BitcoinGUI - - Bitcoin Wallet - Bitcoin novčanik - - - + Sign &message... - + &Potpišite poruku... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Usklađivanje s mrežom ... - + &Overview &Pregled - + Show general overview of wallet Prikaži opći pregled novčanika - + &Transactions &Transakcije - + Browse transaction history Pretraži povijest transakcija - - &Address Book - &Adresar - - - + Edit the list of stored addresses and labels Uređivanje popisa pohranjenih adresa i oznaka - - &Receive coins - &Primanje novca - - - + Show the list of addresses for receiving payments Prikaži popis adresa za primanje isplate - - &Send coins - &Slanje novca - - - - Prove you control an address - Dokažite da posjedujete adresu - - - + E&xit &Izlaz - + Quit application Izlazak iz programa - - &About %1 - &Više o %1 + + Show information about CasinoCoin + Prikaži informacije o CasinoCoinu - - Show information about Bitcoin - Prikaži informacije o Bitcoinu - - - + About &Qt Više o &Qt - + Show information about Qt Prikaži informacije o Qt - + &Options... &Postavke - + &Encrypt Wallet... - + &Šifriraj novčanik... - + &Backup Wallet... - + &Backup novčanika... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Promijena lozinke... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Importiranje blokova sa diska... - - &Export... - &Izvoz... + + Reindexing blocks on disk... + Re-indeksiranje blokova na disku... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Slanje novca na casinocoin adresu - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Promijeni postavke konfiguracije za casinocoin - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - Izvoz podataka iz trenutnog taba u datoteku - - - - Encrypt or decrypt wallet - Šifriranje ili dešifriranje novčanika - - - + Backup wallet to another location Napravite sigurnosnu kopiju novčanika na drugoj lokaciji - + Change the passphrase used for wallet encryption Promijenite lozinku za šifriranje novčanika - + &Debug window - + Open debugging and diagnostic console - + &Verify message... - - Verify a message signature + + + CasinoCoin + CasinoCoin + + + + Wallet + Novčanik + + + + &Send - + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + &O CasinoCoinu + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Datoteka - + &Settings &Konfiguracija - + &Help &Pomoć - + Tabs toolbar Traka kartica - - Actions toolbar - Traka akcija - - - - + + [testnet] [testnet] - - - Bitcoin client + + CasinoCoin client + CasinoCoin klijent + + + + %n active connection(s) to CasinoCoin network + %n aktivna veza na CasinoCoin mrežu%n aktivne veze na CasinoCoin mrežu%n aktivnih veza na CasinoCoin mrežu + + + + No block source available... - - - %n active connection(s) to Bitcoin network - %n aktivna veza na Bitcoin mrežu%n aktivne veze na Bitcoin mrežu%n aktivnih veza na Bitcoin mrežu + + + Processed %1 of %2 (estimated) blocks of transaction history. + - - Downloaded %1 blocks of transaction history. - Preuzeto %1 blokova povijesti transakcije. + + Processed %1 blocks of transaction history. + Obrađeno %1 blokova povijesti transakcije. - - %n second(s) ago - prije %n sekundeprije %n sekundeprije %n sekundi + + %n hour(s) + - - %n minute(s) ago - prije %n minuteprije %n minuteprije %n minuta + + %n day(s) + - - %n hour(s) ago - prije %n sataprije %n sataprije %n sati - - - - %n day(s) ago - prije %n danaprije %n danaprije %n dana + + %n week(s) + - + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + Greška + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Ažurno - + Catching up... Ažuriranje... - - Last received block was generated %1. - Zadnji primljeni blok je generiran %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Ova transakcija je preko ograničenja veličine. Možete ju ipak poslati za naknadu od %1, koja se daje čvorovima koji procesiraju vaše transakcije i tako podržavate mrežu. Želite li platiti naknadu? - - - + Confirm transaction fee - + Sent transaction Poslana transakcija - + Incoming transaction Dolazna transakcija - + Date: %1 Amount: %2 Type: %3 @@ -582,538 +643,485 @@ Adresa:%4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Novčanik je <b>šifriran</b> i trenutno <b>otključan</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Novčanik je <b>šifriran</b> i trenutno <b>zaključan</b> - - Backup Wallet - Backup novčanika - - - - Wallet Data (*.dat) - Podaci novčanika (*.dat) - - - - Backup Failed - Backup nije uspio - - - - There was an error trying to save the wallet data to the new location. - Došlo je do pogreške kod spremanja podataka novčanika na novu lokaciju. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - Prikaz - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Izaberite željeni najmanji dio bitcoina koji će biti prikazan u sučelju i koji će se koristiti za plaćanje. - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address Izmjeni adresu - + &Label &Oznaka - + The label associated with this address book entry Oznaka ovog upisa u adresar - + &Address &Adresa - + The address associated with this address book entry. This can only be modified for sending addresses. Adresa ovog upisa u adresar. Može se mjenjati samo kod adresa za slanje. - + New receiving address Nova adresa za primanje - + New sending address Nova adresa za slanje - + Edit receiving address Uredi adresu za primanje - + Edit sending address Uredi adresu za slanje - + The entered address "%1" is already in the address book. Upisana adresa "%1" je već u adresaru. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Upisana adresa "%1" nije valjana casinocoin adresa. - + Could not unlock wallet. Ne mogu otključati novčanik. - + New key generation failed. Stvaranje novog ključa nije uspjelo. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + verzija - + Usage: Upotreba: - - options + + command-line options - + UI options - + UI postavke - + Set language, for example "de_DE" (default: system locale) - + Start minimized Pokreni minimiziran - + Show splash screen on startup (default: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Postavke + + + + &Main + &Glavno + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Plati &naknadu za transakciju - - Main - Glavno + + Automatically start CasinoCoin after logging in to the system. + Automatski pokreni CasinoCoin kad se uključi računalo - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Neobavezna naknada za transakciju po kB koja omogućuje da se vaša transakcija obavi brže. Većina transakcija ima 1 kB. Preporučena naknada je 0.01. + + &Start CasinoCoin on system login + &Pokreni CasinoCoin kod pokretanja sustava - - &Start Bitcoin on system login + + Reset all client options to default. - - Automatically start Bitcoin after logging in to the system + + &Reset Options - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message + + &Network - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Možete potpisati poruke sa svojom adresom kako bi dokazali da ih posjedujete. Budite oprezni da ne potpisujete ništa mutno, jer bi vas phishing napadi mogli na prevaru natjerati da prepišete svoj identitet njima. Potpisujte samo detaljno objašnjene izjave sa kojima se slažete. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automatski otvori port CasinoCoin klijenta na ruteru. To radi samo ako ruter podržava UPnP i ako je omogućen. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Odaberite adresu iz adresara - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Zalijepi adresu iz međuspremnika - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Upišite poruku koju želite potpisati ovdje - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Kliknite "Potpiši poruku" za potpis - - - - Sign a message to prove you own this address - Potpišite poruku kako bi dokazali da posjedujete ovu adresu - - - - &Sign Message - &Potpišite poruku - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Unesite Bitcoin adresu (npr. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Greška u potpisivanju - - - - %1 is not a valid address. - Upisana adresa "%1" nije valjana bitcoin adresa. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Privatni ključ za %1 nije dostupan. - - - - Sign failed - Potpis nije uspio - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Mapiraj port koristeći &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automatski otvori port Bitcoin klijenta na ruteru. To radi samo ako ruter podržava UPnP i ako je omogućen. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Spojite se na Bitcon mrežu putem SOCKS proxy-a (npr. kod povezivanja kroz Tor) - - &Connect through SOCKS4 proxy: - &Povezivanje putem SOCKS4 proxy-a: + + &Connect through SOCKS proxy: + &Povezivanje putem SOCKS proxy-a: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Spojite se na Bitcon mrežu putem SOCKS4 proxy-a (npr. kod povezivanja kroz Tor) - - - + Proxy &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) IP adresa proxy-a (npr. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Port od proxy-a (npr. 1234) + + &Port: + - - - OptionsDialog - - Options - Postavke + + Port of the proxy (e.g. 9050) + Port od proxy-a (npr. 9050) + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + Prikaži samo ikonu u sistemskoj traci nakon minimiziranja prozora + + + + &Minimize to the tray instead of the taskbar + &Minimiziraj u sistemsku traku umjesto u traku programa + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimizirati umjesto izaći iz aplikacije kada je prozor zatvoren. Kada je ova opcija omogućena, aplikacija će biti zatvorena tek nakon odabira Izlaz u izborniku. + + + + M&inimize on close + M&inimiziraj kod zatvaranja + + + + &Display + &Prikaz + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + &Jedinica za prikazivanje iznosa: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Izaberite željeni najmanji dio casinocoina koji će biti prikazan u sučelju i koji će se koristiti za plaćanje. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + &Prikaži adrese u popisu transakcija + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Upozorenje + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + OverviewPage - + Form Oblik - - - 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - + Balance: Stanje: - - Number of transactions: - Broj transakcija: - - - + Unconfirmed: Nepotvrđene: - + Wallet + Novčanik + + + + Immature: - + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> <b>Nedavne transakcije</b> - + Your current balance Vaše trenutno stanje računa - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Ukupni iznos transakcija koje tek trebaju biti potvrđene, i još uvijek nisu uračunate u trenutni saldo - - Total number of transactions in wallet - Ukupni broj tansakcija u novčaniku - - - - + + out of sync + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + QRCodeDialog - + QR Code Dialog - + QR Code Dijalog - - QR Code - QR kôd - - - + Request Payment Zatraži plaćanje - + Amount: Iznos: - - BTC - BTC - - - + Label: Oznaka - + Message: Poruka: - + &Save As... &Spremi kao... - + Error encoding URI into QR Code. - - Resulting URI too long, try to reduce the text for label / message. + + The entered amount is invalid, please check. - + + Resulting URI too long, try to reduce the text for label / message. + Rezultirajući URI je predug, probajte umanjiti tekst za naslov / poruku. + + + Save QR Code - + PNG Images (*.png) PNG slike (*.png) @@ -1121,125 +1129,146 @@ Adresa:%4 RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Number of connections - + On testnet - + Block chain - + Lanac blokova - + Current number of blocks - + Trenutni broj blokova - + Estimated total blocks - + Procjenjeni ukupni broj blokova - + Last block time - + Posljednje vrijeme bloka - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1247,327 +1276,566 @@ Adresa:%4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Slanje novca - + Send to multiple recipients at once Pošalji k nekoliko primatelja odjednom - - &Add Recipient - + + Add &Recipient + &Dodaj primatelja - + Remove all transaction fields Obriši sva polja transakcija - + Clear &All - + Obriši &sve - + Balance: Stanje: - + 123.456 BTC 123,456 BTC - + Confirm the send action Potvrdi akciju slanja - - &Send + + S&end &Pošalji - + <b>%1</b> to %2 (%3) <b>%1</b> do %2 (%3) - + Confirm send coins Potvrdi slanje novca - + Are you sure you want to send %1? Jeste li sigurni da želite poslati %1? - + and i - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Adresa primatelja je nevaljala, molimo provjerite je ponovo. - + The amount to pay must be larger than 0. Iznos mora biti veći od 0. - + The amount exceeds your balance. - + Iznos je veći od stanja računa. - + The total exceeds your balance when the %1 transaction fee is included. - + Iznos je veći od stanja računa kad se doda naknada za transakcije od %1. - + Duplicate address found, can only send to each address once per send operation. + Pronašli smo adresu koja se ponavlja. U svakom plaćanju program može svaku adresu koristiti samo jedanput. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Generirani novčići moraju pričekati nastanak 120 blokova prije nego što ih je moguće potrošiti. Kad ste generirali taj blok, on je bio emitiran u mrežu kako bi bio dodan postojećim lancima blokova. Ako ne uspije biti dodan, njegov status bit će promijenjen u "nije prihvatljiv" i on neće biti potrošiv. S vremena na vrijeme tako nešto se može desiti ako neki drugi nod približno istovremeno generira blok. SendCoinsEntry - + Form Oblik - + A&mount: &Iznos: - + Pay &To: &Primatelj plaćanja: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Unesite oznaku za ovu adresu kako bi ju dodali u vaš adresar - + &Label: &Oznaka: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresa za slanje plaćanja (npr. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Odaberite adresu iz adresara - + Alt+A Alt+A - + Paste address from clipboard Zalijepi adresu iz međuspremnika - + Alt+P Alt+P - + Remove this recipient Ukloni ovog primatelja - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Unesite Bitcoin adresu (npr. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Unesite CasinoCoin adresu (npr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Potpišite poruku + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Možete potpisati poruke sa svojom adresom kako bi dokazali da ih posjedujete. Budite oprezni da ne potpisujete ništa mutno, jer bi vas phishing napadi mogli na prevaru natjerati da prepišete svoj identitet njima. Potpisujte samo detaljno objašnjene izjave sa kojima se slažete. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Unesite CasinoCoin adresu (npr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Odaberite adresu iz adresara + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Zalijepi adresu iz međuspremnika + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Upišite poruku koju želite potpisati ovdje + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + Obriši &sve + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Unesite CasinoCoin adresu (npr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Unesite CasinoCoin adresu (npr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Otvori za %1 blokova - - - + Open until %1 Otvoren do %1 - - %1/offline? - %1 nije dostupan? + + %1/offline + %1 nije dostupan - + %1/unconfirmed %1/nepotvrđeno - + %1 confirmations %1 potvrda - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + - + + Date + Datum + + + + Source + + + + + Generated + Generiran + + + + + From + Od + + + + + + To + Za + + + + + own address + + + + + label + oznaka + + + + + + + + Credit + Uplaćeno + + + + matures in %n more block(s) + + + + + not accepted + Nije prihvaćeno + + + + + + + Debit + Zaduženje + + + + Transaction fee + Naknada za transakciju + + + + Net amount + Neto iznos + + + + Message + Poruka + + + + Comment + Komentar + + + + Transaction ID + + + + + Generated coins must mature 120 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. + Generirani novčići moraju pričekati nastanak 120 blokova prije nego što ih je moguće potrošiti. Kad ste generirali taj blok, on je bio emitiran u mrežu kako bi bio dodan postojećim lancima blokova. Ako ne uspije biti dodan, njegov status bit će promijenjen u "nije prihvaćen" i on neće biti potrošiv. S vremena na vrijeme tako nešto se može desiti ako neki drugi nod generira blok u približno isto vrijeme. + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + Iznos + + + + true + + + + + false + + + + , has not been successfully broadcast yet , još nije bio uspješno emitiran - - - , broadcast through %1 node - , emitiran kroz nod %1 + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , emitiran kroz nodove %1 - - - - <b>Date:</b> - <b>Datum:</b> - - - - <b>Source:</b> Generated<br> - <b>Izvor:</b> Generirano<br> - - - - - <b>From:</b> - <b>Od:</b> - - - + unknown nepoznato - - - - - <b>To:</b> - <b>Za:</b> - - - - (yours, label: - (tvoje, oznaka: - - - - (yours) - (tvoje) - - - - - - - <b>Credit:</b> - <b>Uplaćeno:</b> - - - - (%1 matures in %2 more blocks) - (%1 stasava za %2 dodatna bloka) - - - - (not accepted) - (Nije prihvaćeno) - - - - - - <b>Debit:</b> - <b>Potrošeno:</b> - - - - <b>Transaction fee:</b> - <b>Naknada za transakciju:</b> - - - - <b>Net amount:</b> - <b>Neto iznos:</b> - - - - Message: - Poruka: - - - - Comment: - Komentar: - - - - Transaction ID: - ID transakcije: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Generirani novčići moraju pričekati nastanak 120 blokova prije nego što ih je moguće potrošiti. Kad ste generirali taj blok, on je bio emitiran u mrežu kako bi bio dodan postojećim lancima blokova. Ako ne uspije biti dodan, njegov status bit će promijenjen u "nije prihvaćen" i on neće biti potrošiv. S vremena na vrijeme tako nešto se može desiti ako neki drugi nod generira blok u približno isto vrijeme. - TransactionDescDialog - + Transaction details Detalji transakcije - + This pane shows a detailed description of the transaction Ova panela prikazuje detaljni opis transakcije @@ -1575,117 +1843,117 @@ Adresa:%4 TransactionTableModel - + Date Datum - + Type Tip - + Address Adresa - + Amount Iznos - - Open for %n block(s) - Otvoren za %n blokaOtvoren za %n blokovaOtvoren za %n blokova + + Open for %n more block(s) + - + Open until %1 Otvoren do %1 - + Offline (%1 confirmations) Nije na mreži (%1 potvrda) - + Unconfirmed (%1 of %2 confirmations) Nepotvrđen (%1 od %2 potvrda) - + Confirmed (%1 confirmations) Potvrđen (%1 potvrda) - - Mined balance will be available in %n more blocks - Saldo iskovanih novčićća bit de dostupan nakon %n dodatnog blokaSaldo iskovanih novčićća bit de dostupan nakon %n dodatnih blokovaSaldo iskovanih novčićća bit de dostupan nakon %n dodatnih blokova + + Mined balance will be available when it matures in %n more block(s) + - + This block was not received by any other nodes and will probably not be accepted! Generirano - Upozorenje: ovaj blok nije bio primljen od strane bilo kojeg drugog noda i vjerojatno neće biti prihvaćen! - + Generated but not accepted Generirano, ali nije prihvaćeno - + Received with Primljeno s - + Received from Primljeno od - + Sent to Poslano za - + Payment to yourself Plaćanje samom sebi - + Mined Rudareno - + (n/a) (n/d) - + Transaction status. Hover over this field to show number of confirmations. Status transakcije - + Date and time that the transaction was received. Datum i vrijeme kad je transakcija primljena - + Type of transaction. Vrsta transakcije. - + Destination address of transaction. Odredište transakcije - + Amount removed from or added to balance. Iznos odbijen od ili dodan k saldu. @@ -1693,818 +1961,961 @@ Adresa:%4 TransactionView - - + + All Sve - + Today Danas - + This week Ovaj tjedan - + This month Ovaj mjesec - + Last month Prošli mjesec - + This year Ove godine - + Range... Raspon... - + Received with Primljeno s - + Sent to Poslano za - + To yourself Tebi - + Mined Rudareno - + Other Ostalo - + Enter address or label to search Unesite adresu ili oznaku za pretraživanje - + Min amount Min iznos - + Copy address Kopirati adresu - + Copy label Kopirati oznaku - + Copy amount Kopiraj iznos - + + Copy transaction ID + + + + Edit label Izmjeniti oznaku - + Show transaction details - + Export Transaction Data Izvoz podataka transakcija - + Comma separated file (*.csv) Datoteka podataka odvojenih zarezima (*.csv) - + Confirmed Potvrđeno - + Date Datum - + Type Tip - + Label Oznaka - + Address Adresa - + Amount Iznos - + ID ID - + Error exporting Izvoz pogreške - + Could not write to file %1. Ne mogu pisati u datoteku %1. - + Range: Raspon: - + to za - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopiraj trenutno odabranu adresu u međuspremnik - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Slanje... + + Send Coins + Slanje novca - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Minimiziraj u sistemsku traku umjesto u traku programa + + Export the data in the current tab to a file + Izvoz podataka iz trenutnog taba u datoteku - - Show only a tray icon after minimizing the window - Prikaži samo ikonu u sistemskoj traci nakon minimiziranja prozora - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimizirati umjesto izaći iz aplikacije kada je prozor zatvoren. Kada je ova opcija omogućena, aplikacija će biti zatvorena tek nakon odabira Izlaz u izborniku. + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - Bitcoin verzija + + CasinoCoin version + CasinoCoin verzija - + Usage: Upotreba: - - Send command to -server or bitcoind - Pošalji komandu usluzi -server ili bitcoind + + Send command to -server or casinocoind + Pošalji komandu usluzi -server ili casinocoind - + List commands Prikaži komande - + Get help for a command Potraži pomoć za komandu - + Options: Postavke: - - Specify configuration file (default: bitcoin.conf) - Odredi konfiguracijsku datoteku (ugrađeni izbor: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Odredi konfiguracijsku datoteku (ugrađeni izbor: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Odredi proces ID datoteku (ugrađeni izbor: bitcoin.pid) + + Specify pid file (default: casinocoind.pid) + Odredi proces ID datoteku (ugrađeni izbor: casinocoin.pid) - - Generate coins - Generiraj novčiće - - - - Don't generate coins - Ne generiraj novčiće - - - + Specify data directory Odredi direktorij za datoteke - + Set database cache size in megabytes (default: 25) - + Postavi cache za bazu podataka u MB (zadano:25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Slušaj na <port>u (default: 47950 ili testnet: 17950) - - Specify connection timeout (in milliseconds) - Odredi vremenski prozor za spajanje na mrežu (u milisekundama) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Slušaj na <port>u (default: 8333 ili testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Održavaj najviše <n> veza sa članovima (default: 125) - - Connect only to the specified node - Poveži se samo sa određenim nodom - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Prag za odspajanje članova koji se čudno ponašaju (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Broj sekundi koliko se članovima koji se čudno ponašaju neće dopustiti da se opet spoje (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maksimalni buffer za primanje po vezi, <n>*1000 bajta (default: 10000) - - - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maksimalni buffer za slanje po vezi, <n>*1000 bajta (default: 10000) - - - - Detach block and address databases. Increases shutdown time (default: 0) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Prihvaćaj JSON-RPC povezivanje na portu broj <port> (ugrađeni izbor: 47970 or testnet: 17970) + + + Accept command line and JSON-RPC commands Prihvati komande iz tekst moda i JSON-RPC - + Run in the background as a daemon and accept commands Izvršavaj u pozadini kao uslužnik i prihvaćaj komande - + Use the test network Koristi test mrežu - - Output extra debugging information - Dodaj sve dodatne informacije debuggiranja na izlaz - - - - Prepend debug output with timestamp - Dodaj izlaz debuga na početak sa vremenskom oznakom - - - - Send trace/debug info to console instead of debug.log file - Šalji trace/debug informacije na konzolu umjesto u debug.log datoteku - - - - Send trace/debug info to debugger - Pošalji trace/debug informacije u debugger - - - - Username for JSON-RPC connections - Korisničko ime za JSON-RPC veze - - - - Password for JSON-RPC connections - Lozinka za JSON-RPC veze - - - - Listen for JSON-RPC connections on <port> (default: 8332) - Prihvaćaj JSON-RPC povezivanje na portu broj <port> (ugrađeni izbor: 8332) - - - - Allow JSON-RPC connections from specified IP address - Dozvoli JSON-RPC povezivanje s određene IP adrese - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Pošalji komande nodu na adresi <ip> (ugrađeni izbor: 127.0.0.1) - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - Podesi memorijski prostor za ključeve na <n> (ugrađeni izbor: 100) - - - - Rescan the block chain for missing wallet transactions - Ponovno pretraži lanac blokova za transakcije koje nedostaju - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - SSL postavke: (za detalje o podešavanju SSL opcija vidi Bitcoin Wiki) - - - - Use OpenSSL (https) for JSON-RPC connections - Koristi OpenSSL (https) za JSON-RPC povezivanje - - - - Server certificate file (default: server.cert) - Uslužnikov SSL certifikat (ugrađeni izbor: server.cert) - - - - Server private key (default: server.pem) - Uslužnikov privatni ključ (ugrađeni izbor: server.pem) - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Prihvaljivi načini šifriranja (ugrađeni izbor: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - - - - - This help message - Ova poruka za pomoć - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Program ne može pristupiti direktoriju s datotekama %s. Bitcoin program je vjerojatno već pokrenut. - - - - Bitcoin - Bitcoin - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - Učitavanje adresa... - - - - Error loading blkindex.dat - Greška kod učitavanja blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - Greška kod učitavanja wallet.dat: Novčanik pokvaren - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Greška kod učitavanja wallet.dat: Novčanik zahtjeva noviju verziju Bitcoina - - - - Wallet needed to be rewritten: restart Bitcoin to complete - Novčanik je trebao prepravak: ponovo pokrenite Bitcoin - - - - Error loading wallet.dat - Greška kod učitavanja wallet.dat - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Greška: priprema transakcije nije uspjela - - - - Sending... - Slanje... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Generirani novčići moraju pričekati nastanak 120 blokova prije nego što ih je moguće potrošiti. Kad ste generirali taj blok, on je bio emitiran u mrežu kako bi bio dodan postojećim lancima blokova. Ako ne uspije biti dodan, njegov status bit će promijenjen u "nije prihvatljiv" i on neće biti potrošiv. S vremena na vrijeme tako nešto se može desiti ako neki drugi nod približno istovremeno generira blok. - - - - Invalid amount - - - - - Insufficient funds - Nedovoljna sredstva - - - - Loading block index... - Učitavanje indeksa blokova... - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - Naknada posredniku po KB-u koja će biti dodana svakoj transakciji koju pošalješ - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - Učitavanje novčanika... - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - Rescaniranje - - - - Done loading - Učitavanje gotovo - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Upozorenje: -paytxfee je podešen na preveliki iznos. To je iznos koji ćete platiti za obradu transakcije. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Upozorenje: Molimo provjerite jesu li datum i vrijeme na vašem računalu točni. Ako vaš sat ide krivo, CasinoCoin neće raditi ispravno. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + Opcije za kreiranje bloka: + + + + Connect only to the specified node(s) + Poveži se samo sa određenim nodom + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + Importiraj blokove sa vanjskog blk000??.dat fajla + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Nevaljala -tor adresa: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + Prihvati samo lance blokova koji se podudaraju sa ugrađenim checkpoint-ovima (default: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + Dodaj izlaz debuga na početak sa vremenskom oznakom + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL postavke: (za detalje o podešavanju SSL opcija vidi CasinoCoin Wiki) + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + Šalji trace/debug informacije na konzolu umjesto u debug.log datoteku + + + + Send trace/debug info to debugger + Pošalji trace/debug informacije u debugger + + + + Set maximum block size in bytes (default: 250000) + Podesite maksimalnu veličinu bloka u bajtovima (default: 250000) + + + + Set minimum block size in bytes (default: 0) + Podesite minimalnu veličinu bloka u bajtovima (default: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Odredi vremenski prozor za spajanje na mrežu u milisekundama (ugrađeni izbor: 5000) + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Pokušaj koristiti UPnP da otvoriš port za uslugu (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Pokušaj koristiti UPnP da otvoriš port za uslugu (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + Korisničko ime za JSON-RPC veze + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Lozinka za JSON-RPC veze + + + + Allow JSON-RPC connections from specified IP address + Dozvoli JSON-RPC povezivanje s određene IP adrese + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Pošalji komande nodu na adresi <ip> (ugrađeni izbor: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Izvršite naredbu kada se najbolji blok promjeni (%s u cmd je zamjenjen sa block hash) + + + + Upgrade wallet to latest format + Nadogradite novčanik u posljednji format. + + + + Set key pool size to <n> (default: 100) + Podesi memorijski prostor za ključeve na <n> (ugrađeni izbor: 100) + + + + Rescan the block chain for missing wallet transactions + Ponovno pretraži lanac blokova za transakcije koje nedostaju + + + + Use OpenSSL (https) for JSON-RPC connections + Koristi OpenSSL (https) za JSON-RPC povezivanje + + + + Server certificate file (default: server.cert) + Uslužnikov SSL certifikat (ugrađeni izbor: server.cert) + + + + Server private key (default: server.pem) + Uslužnikov privatni ključ (ugrađeni izbor: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Prihvaljivi načini šifriranja (ugrađeni izbor: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Ova poruka za pomoć + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Program ne može koristiti %s na ovom računalu (bind returned error %d, %s) + + + + Connect through socks proxy + Poveži se kroz socks proxy + + + + Allow DNS lookups for -addnode, -seednode and -connect + Dozvoli DNS upite za dodavanje nodova i povezivanje + + + + Loading addresses... + Učitavanje adresa... + + + + Error loading wallet.dat: Wallet corrupted + Greška kod učitavanja wallet.dat: Novčanik pokvaren + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Greška kod učitavanja wallet.dat: Novčanik zahtjeva noviju verziju CasinoCoina + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Novčanik je trebao prepravak: ponovo pokrenite CasinoCoin + + + + Error loading wallet.dat + Greška kod učitavanja wallet.dat + + + + Invalid -proxy address: '%s' + Nevaljala -proxy adresa: '%s' + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + Nevaljali iznos za opciju -paytxfee=<amount>: '%s' + + + + Invalid amount + Nevaljali iznos za opciju + + + + Insufficient funds + Nedovoljna sredstva + + + + Loading block index... + Učitavanje indeksa blokova... + + + + Add a node to connect to and attempt to keep the connection open + Unesite nod s kojim se želite spojiti and attempt to keep the connection open + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Program ne može koristiti %s na ovom računalu. CasinoCoin program je vjerojatno već pokrenut. + + + + Fee per KB to add to transactions you send + Naknada posredniku po KB-u koja će biti dodana svakoj transakciji koju pošalješ + + + + Loading wallet... + Učitavanje novčanika... + + + + Cannot downgrade wallet + Nije moguće novčanik vratiti na prijašnju verziju. + + + + Cannot write default address + Nije moguće upisati zadanu adresu. + + + + Rescanning... + Rescaniranje + + + + Done loading + Učitavanje gotovo + + + + To use the %s option + + + + Error - + Greška - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Upozorenje: Molimo provjerite jesu li datum i vrijeme na vašem računalu točni. Ako vaš sat ide krivo, Bitcoin neće raditi ispravno. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index e69453c..05c5637 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -3,116 +3,159 @@ AboutDialog - - About Bitcoin - A Bitcoinról + + About CasinoCoin + A CasinoCoinról - - <b>Bitcoin</b> version - <b>Bitcoin</b> verzió + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> verzió - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + +Ez egy kísérleti program. +MIT/X11 szoftverlicenc alatt kiadva, lásd a mellékelt fájlt COPYING vagy http://www.opensource.org/licenses/mit-license.php. + +Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (http://www.openssl.org/) és kriptográfiai szoftvertben való felhasználásra, írta Eric Young (eay@cryptsoft.com) és UPnP szoftver, írta Thomas Bernard. + + + + Copyright + + + + + The CasinoCoin developers AddressBookPage - + Address Book Címjegyzék - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Ezekkel a Bitcoin-címekkel fogadhatod kifizetéseket. Érdemes lehet minden egyes kifizető számára külön címet létrehozni, hogy könnyebben nyomon követhesd, kitől kaptál már pénzt. - - - + Double-click to edit address or label - Dupla-katt a cím vagy a címke szerkesztéséhez + Dupla-kattintás a cím vagy a címke szerkesztéséhez - + Create a new address Új cím létrehozása - + Copy the currently selected address to the system clipboard A kiválasztott cím másolása a vágólapra - + &New Address - + &Új cím - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Ezekkel a CasinoCoin-címekkel fogadhatod kifizetéseket. Érdemes lehet minden egyes kifizető számára külön címet létrehozni, hogy könnyebben nyomon követhesd, kitől kaptál már pénzt. + + + &Copy Address - + &Cím másolása - + Show &QR Code + &QR kód mutatása + + + + Sign a message to prove you own a CasinoCoin address - - Sign a message to prove you own this address + + Sign &Message - - &Sign Message + + Delete the currently selected address from the list - - Delete the currently selected address from the list. Only sending addresses can be deleted. - A kiválasztott cím törlése a listáról. Csak a küldő címek törölhetőek. + + Export the data in the current tab to a file + Jelenlegi nézet exportálása fájlba - + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Üzenet ellenőrzése, hogy valóban a megjelölt CasinoCoin címekkel van-e aláírva. + + + + &Verify Message + Üzenet ellenőrzése + + + &Delete &Törlés - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Címke &másolása - + &Edit + Sz&erkesztés + + + + Send &Coins - + Export Address Book Data Címjegyzék adatainak exportálása - + Comma separated file (*.csv) Vesszővel elválasztott fájl (*. csv) - + Error exporting Hiba exportálás közben - + Could not write to file %1. %1 nevű fájl nem írható. @@ -120,17 +163,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Címke - + Address Cím - + (no label) (nincs címke) @@ -138,432 +181,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Kulcsszó párbeszédablak - + Enter passphrase Add meg a jelszót - + New passphrase Új jelszó - + Repeat new passphrase Új jelszó újra - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Írd be az új jelszót a tárcához.<br/>Használj legalább 10<br/>véletlenszerű karaktert</b> vagy <b>legalább nyolc szót</b>. - + Encrypt wallet Tárca kódolása - + This operation needs your wallet passphrase to unlock the wallet. A tárcád megnyitásához a műveletnek szüksége van a tárcád jelszavára. - + Unlock wallet Tárca megnyitása - + This operation needs your wallet passphrase to decrypt the wallet. A tárcád dekódolásához a műveletnek szüksége van a tárcád jelszavára. - + Decrypt wallet Tárca dekódolása - + Change passphrase Jelszó megváltoztatása - + Enter the old and new passphrase to the wallet. Írd be a tárca régi és új jelszavát. - + Confirm wallet encryption Biztosan kódolni akarod a tárcát? - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - FIGYELEM: Ha kódolod a tárcát, és elveszíted a jelszavad, akkor <b>AZ ÖSSZES BITCOINODAT IS EL FOGOD VESZÍTENI!</b> -Biztosan kódolni akarod a tárcát? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Figyelem: Ha kódolod a tárcát, és elveszíted a jelszavad, akkor <b>AZ ÖSSZES CASINOCOINODAT IS EL FOGOD VESZÍTENI!</b> - - + + Are you sure you wish to encrypt your wallet? + Biztosan kódolni akarod a tárcát? + + + + 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. + FONTOS: A pénztárca-fájl korábbi mentéseit ezzel az új, titkosított pénztárca-fájllal kell helyettesíteni. Biztonsági okokból a pénztárca-fájl korábbi titkosítás nélküli mentései haszontalanná válnak amint elkezdi használni az új, titkosított pénztárcát. + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted Tárca kódolva - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin will close now to finish the encryption process. Ne feledd, hogy a tárca titkosítása sem nyújt teljes védelmet az adathalász programok fertőzésével szemben. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed Tárca kódolása sikertelen. - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Tárca kódolása belső hiba miatt sikertelen. A tárcád nem lett kódolva. - - + + The supplied passphrases do not match. A megadott jelszavak nem egyeznek. - + Wallet unlock failed Tárca megnyitása sikertelen - - - + + + The passphrase entered for the wallet decryption was incorrect. Hibás jelszó. - + Wallet decryption failed Dekódolás sikertelen. - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Jelszó megváltoztatva. BitcoinGUI - - Bitcoin Wallet - Bitcoin-tárca - - - + Sign &message... - + Üzenet aláírása... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Szinkronizálás a hálózattal... - + &Overview &Áttekintés - + Show general overview of wallet Tárca általános áttekintése - + &Transactions &Tranzakciók - + Browse transaction history Tranzakciótörténet megtekintése - - &Address Book - Cím&jegyzék - - - + Edit the list of stored addresses and labels Tárolt címek és címkék listájának szerkesztése - - &Receive coins - Érmék &fogadása - - - + Show the list of addresses for receiving payments Kiizetést fogadó címek listája - - &Send coins - Érmék &küldése - - - - Prove you control an address - - - - + E&xit &Kilépés - + Quit application Kilépés - - &About %1 - &A %1-ról + + Show information about CasinoCoin + Információk a CasinoCoinról - - Show information about Bitcoin - Információk a Bitcoinról - - - + About &Qt - + A &Qt-ról - + Show information about Qt - + Információk a Qt ról - + &Options... &Opciók... - + &Encrypt Wallet... - + Tárca &kódolása... - + &Backup Wallet... - + &Bisztonsági másolat készítése a Tárcáról - + &Change Passphrase... - - - - - ~%n block(s) remaining - + Jelszó &megváltoztatása... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + A blokkok importálása lemezről... - - &Export... - &Exportálás... + + Reindexing blocks on disk... + A blokkok lemezen történő ujraindexelése... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Érmék küldése megadott címre - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + CasinoCoin konfigurációs opciók - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - Tárca kódolása vagy dekódolása - - - + Backup wallet to another location - + Biztonsági másolat készítése a Tárcáról egy másik helyre - + Change the passphrase used for wallet encryption Tárcakódoló jelszó megváltoztatása - + &Debug window - + &Debug ablak - + Open debugging and diagnostic console - + Hibakereső és diagnosztikai konzol megnyitása - + &Verify message... + Üzenet &valódiságának ellenőrzése + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Tárca + + + + &Send - - Verify a message signature + + &Receive - + + &Addresses + + + + + &About CasinoCoin + &A CasinoCoinról + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + A pénztárcájához tartozó privát kulcsok titkosítása + + + + Sign messages with your CasinoCoin addresses to prove you own them + Üzenet aláírása a CasinoCoin címmel, amivel bizonyítja, hogy a cím az ön tulajdona. + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Annak ellenőrzése, hogy az üzenetek valóban a megjelölt CasinoCoin címekkel vannak-e alaírva + + + &File &Fájl - + &Settings &Beállítások - + &Help &Súgó - + Tabs toolbar Fül eszköztár - - Actions toolbar - Parancsok eszköztár - - - - + + [testnet] [teszthálózat] - - - Bitcoin client + + CasinoCoin client + CasinoCoin kliens + + + + %n active connection(s) to CasinoCoin network + %n aktív kapcsolat a CasinoCoin-hálózattal%n aktív kapcsolat a CasinoCoin-hálózattal + + + + No block source available... - - - %n active connection(s) to Bitcoin network - %n aktív kapcsolat a Bitcoin-hálózattal%n aktív kapcsolat a Bitcoin-hálózattal + + + Processed %1 of %2 (estimated) blocks of transaction history. + - - Downloaded %1 blocks of transaction history. - %1 blokk letöltve a tranzakciótörténetből. + + Processed %1 blocks of transaction history. + A tranzakció-történet %1 blokkja feldolgozva. - - %n second(s) ago - %n másodperccel ezelőtt%n másodperccel ezelőtt + + %n hour(s) + - - %n minute(s) ago - %n perccel ezelőtt%n perccel ezelőtt + + %n day(s) + - - %n hour(s) ago - %n órával ezelőtt%n órával ezelőtt - - - - %n day(s) ago - %n nappal ezelőtt%n nappal ezelőtt + + %n week(s) + - + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Naprakész - + Catching up... Frissítés... - - Last received block was generated %1. - Az utolsóként kapott blokk generálva: %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Ez a tranzakció túllépi a mérethatárt, de %1 tranzakciós díj ellenében így is elküldheted. Ezt a plusz összeget a tranzakcióidat feldolgozó csomópontok kapják, így magát a hálózatot támogatod vele. Hajlandó vagy megfizetni a díjat? - - - + Confirm transaction fee - + Tranzakciós díj jóváhagyása - + Sent transaction Tranzakció elküldve. - + Incoming transaction Beérkező tranzakció - + Date: %1 Amount: %2 Type: %3 @@ -576,665 +647,633 @@ Cím: %4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Tárca <b>kódolva</b> és jelenleg <b>nyitva</b>. - + Wallet is <b>encrypted</b> and currently <b>locked</b> Tárca <b>kódolva</b> és jelenleg <b>zárva</b>. - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - Megjelenítés - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Válaszd ki az interfészen és érmék küldésekor megjelenítendő alapértelmezett alegységet. - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address Cím szerkesztése - + &Label Cím&ke - + The label associated with this address book entry A címhez tartozó címke - + &Address &Cím - + The address associated with this address book entry. This can only be modified for sending addresses. Az ehhez a címjegyzék-bejegyzéshez tartozó cím. Ez csak a küldő címeknél módosítható. - + New receiving address Új fogadó cím - + New sending address Új küldő cím - + Edit receiving address Fogadó cím szerkesztése - + Edit sending address Küldő cím szerkesztése - + The entered address "%1" is already in the address book. A megadott "%1" cím már szerepel a címjegyzékben. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + A megadott "%1" cím nem egy érvényes CasinoCoin-cím. - + Could not unlock wallet. Tárca feloldása sikertelen - + New key generation failed. Új kulcs generálása sikertelen - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + verzió - + Usage: Használat: - - options - + + command-line options + parancssoros opciók - + UI options - + UI opciók - + Set language, for example "de_DE" (default: system locale) - + Start minimized Indítás lekicsinyítve - + Show splash screen on startup (default: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Opciók + + + + &Main + &Fő + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Tranzakciós &díj fizetése - - Main - + + Automatically start CasinoCoin after logging in to the system. + Induljon el a CasinoCoin a számítógép bekapcsolásakor - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + + &Start CasinoCoin on system login + &Induljon el a számítógép bekapcsolásakor + + + + Reset all client options to default. - - &Start Bitcoin on system login + + &Reset Options - - Automatically start Bitcoin after logging in to the system + + &Network - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + A CasinoCoin-kliens portjának automatikus megnyitása a routeren. Ez csak akkor működik, ha a routered támogatja az UPnP-t és az engedélyezve is van rajta. - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Válassz egy címet a címjegyzékből - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Cím beillesztése a vágólapról - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adj meg egy Bitcoin-címet (pl.: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L ) - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP &UPnP port-feltérképezés - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - A Bitcoin-kliens portjának automatikus megnyitása a routeren. Ez csak akkor működik, ha a routered támogatja az UPnP-t és az engedélyezve is van rajta. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + SOCKS proxyn keresztüli csatlakozás a CasinoCoin hálózatához (pl. Tor-on keresztüli csatlakozás esetén) - - &Connect through SOCKS4 proxy: - &Csatlakozás SOCKS4 proxyn keresztül: + + &Connect through SOCKS proxy: + &Csatlakozás SOCKS proxyn keresztül: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - SOCKS4 proxyn keresztüli csatlakozás a Bitcoin hálózatához (pl. Tor-on keresztüli csatlakozás esetén) - - - + Proxy &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Proxy IP címe (pl.: 127.0.0.1) - - Port of the proxy (e.g. 1234) - Proxy portja (pl.: 1234) + + &Port: + - - - OptionsDialog - - Options - Opciók + + Port of the proxy (e.g. 9050) + Proxy portja (pl.: 9050) + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + Kicsinyítés után csak eszköztár-ikont mutass + + + + &Minimize to the tray instead of the taskbar + &Kicsinyítés a tálcára az eszköztár helyett + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Az alkalmazásból való kilépés helyett az eszköztárba kicsinyíti az alkalmazást az ablak bezárásakor. Ez esetben az alkalmazás csak a Kilépés menüponttal zárható be. + + + + M&inimize on close + K&icsinyítés záráskor + + + + &Display + &Megjelenítés + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + &Mértékegység: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Válaszd ki az interfészen és érmék küldésekor megjelenítendő alapértelmezett alegységet. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + &Címek megjelenítése a tranzakciólistában + + + + &OK + + + + + &Cancel + Megszakítás + + + + &Apply + Alkalmazás + + + + default + alapértelmezett + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Figyelem + + + + + This setting will take effect after restarting CasinoCoin. + Ez a beállítás a CasinoCoin ujraindítása után lép érvénybe. + + + + The supplied proxy address is invalid. + OverviewPage - + Form Űrlap - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + A kijelzett információ lehet, hogy elavult. A pénztárcája automatikusan szinkronizálja magát a CasinoCoin hálózattal miután a kapcsolat létrejön, de ez e folyamat még nem fejeződött be. - + Balance: Egyenleg: - - Number of transactions: - Tranzakciók száma: - - - + Unconfirmed: Megerősítetlen: - + Wallet + Tárca + + + + Immature: - + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> <b>Legutóbbi tranzakciók</b> - + Your current balance Aktuális egyenleged - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Még megerősítésre váró, a jelenlegi egyenlegbe be nem számított tranzakciók - - Total number of transactions in wallet - Tárca összes tranzakcióinak száma - - - - + + out of sync + Nincs szinkronban. + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - + QR kód párbeszédablak - - QR Code - - - - + Request Payment - + Fizetés kérése - + Amount: - + Összeg: - - BTC - - - - + Label: - + Címke: - + Message: Üzenet: - + &Save As... - + Mentés má&sként - + Error encoding URI into QR Code. - + Hiba lépett fel az URI QR kóddá alakításakor - + + The entered amount is invalid, please check. + A megadott összeg nem érvényes. Kérem ellenőrizze. + + + Resulting URI too long, try to reduce the text for label / message. - + A keletkezett URI túl hosszú, próbálja meg csökkenteni a cimkeszöveg / üzenet méretét. - + Save QR Code - + QR kód mentése - + PNG Images (*.png) - + PNG Képfájlok (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Kliens néve - - - - - - - - - + + + + + + + + + + N/A - + Nem elérhető - + Client version - + Kliens verzió - + &Information + &Információ + + + + Using OpenSSL version - - Client - - - - + Startup time - + Bekapcsolás ideje - + Network - + Hálózat - + Number of connections - + Kapcsolatok száma - + On testnet - + Teszthálózaton - + Block chain - + Blokklánc - + Current number of blocks - + Aktuális blokkok száma - + Estimated total blocks - + Becsült összes blokk - + Last block time - + Utolsó blokk ideje - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open + &Megnyitás + + + + Command-line options - + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + &Konzol - + Build date + Fordítás dátuma + + + + CasinoCoin - Debug window - + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console + Konzol törlése + + + + Welcome to the CasinoCoin RPC console. - - Welcome to the Bitcoin RPC console. - - - - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Navigálhat a fel és le nyilakkal, és <b>Ctrl-L</b> -vel törölheti a képernyőt. - + Type <b>help</b> for an overview of available commands. @@ -1242,328 +1281,567 @@ Cím: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Érmék küldése - + Send to multiple recipients at once Küldés több címzettnek egyszerre - - &Add Recipient - + + Add &Recipient + &Címzett hozzáadása - + Remove all transaction fields - + Az összes tranzakciós mező eltávolítása - + Clear &All - + Mindent &töröl - + Balance: Egyenleg: - + 123.456 BTC 123.456 BTC - + Confirm the send action Küldés megerősítése - - &Send + + S&end &Küldés - + <b>%1</b> to %2 (%3) <b>%1</b> %2-re (%3) - + Confirm send coins Küldés megerősítése - + Are you sure you want to send %1? Valóban el akarsz küldeni %1-t? - + and és - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. A címzett címe érvénytelen, kérlek, ellenőrizd. - + The amount to pay must be larger than 0. A fizetendő összegnek nagyobbnak kell lennie 0-nál. - + The amount exceeds your balance. - + Nincs ennyi casinocoin az egyenlegeden. - + The total exceeds your balance when the %1 transaction fee is included. - + A küldeni kívánt összeg és a %1 tranzakciós díj együtt meghaladja az egyenlegeden rendelkezésedre álló összeget. - + Duplicate address found, can only send to each address once per send operation. + Többször szerepel ugyanaz a cím. Egy küldési műveletben egy címre csak egyszer lehet küldeni. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Hiba: a tranzakciót elutasították. Ezt az okozhatja, ha már elköltöttél valamennyi érmét a tárcádból például ha a wallet.dat-od egy másolatát használtad, és így az elköltés csak abban lett jelölve, de itt nem. SendCoinsEntry - + Form Űrlap - + A&mount: Összeg: - + Pay &To: Címzett: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Milyen címkével kerüljön be ez a cím a címtáradba? - + &Label: Címke: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Címzett címe (pl.: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L ) - - - + Choose address from address book Válassz egy címet a címjegyzékből - + Alt+A Alt+A - + Paste address from clipboard Cím beillesztése a vágólapról - + Alt+P Alt+P - + Remove this recipient Címzett eltávolítása - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adj meg egy Bitcoin-címet (pl.: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L ) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adj meg egy CasinoCoin-címet (pl.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2 ) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + Üzenet aláírása... + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Aláírhat a címeivel üzeneteket, amivel bizonyíthatja, hogy a címek az önéi. Vigyázzon, hogy ne írjon alá semmi félreérthetőt, mivel a phising támadásokkal megpróbálhatják becsapni, hogy az azonosságát átírja másokra. Csak olyan részletes állításokat írjon alá, amivel egyetért. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adj meg egy CasinoCoin-címet (pl.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2 ) + + + + + Choose an address from the address book + Válassz egy címet a címjegyzékből + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Cím beillesztése a vágólapról + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Ide írja az aláírandó üzenetet + + + + Signature + + + + + Copy the current signature to the system clipboard + A jelenleg kiválasztott aláírás másolása a rendszer-vágólapra + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + Mindent &töröl + + + + &Verify Message + Üzenet ellenőrzése + + + + Enter the signing 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. + Írja be az aláírás címét, az üzenetet (ügyelve arra, hogy az új-sor, szóköz, tab, stb. karaktereket is pontosan) és az aláírást az üzenet ellenőrzéséhez. Ügyeljen arra, ne gondoljon többet az aláírásról, mint amennyi az aláírt szövegben ténylegesen áll, hogy elkerülje a köztes-ember (man-in-the-middle) támadást. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adj meg egy CasinoCoin-címet (pl.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2 ) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adj meg egy CasinoCoin-címet (pl.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2 ) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + Adja meg a CasinoCoin aláírást + + + + + The entered address is invalid. + A megadott cím nem érvényes. + + + + + + + Please check the address and try again. + Ellenőrizze a címet és próbálja meg újra. + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [teszthálózat] TransactionDesc - - Open for %1 blocks - Megnyitva %1 blokkra - - - + Open until %1 Megnyitva %1-ig - - %1/offline? - %1/offline? + + %1/offline + - + %1/unconfirmed %1/megerősítetlen - + %1 confirmations %1 megerősítés - - <b>Status:</b> - <b>Állapot:</b> + + Status + Állapot + + + + , broadcast through %n node(s) + - - , has not been successfully broadcast yet - , még nem sikerült elküldeni. + + Date + Dátum - - , broadcast through %1 node - , %1 csomóponton keresztül elküldve. - - - - , broadcast through %1 nodes - , elküldve %1 csomóponton keresztül. - - - - <b>Date:</b> - <b>Dátum:</b> - - - - <b>Source:</b> Generated<br> - <b>Forrás:</b> Generálva <br> - - - - - <b>From:</b> - <b>Űrlap:</b> - - - - unknown - ismeretlen - - - - - - <b>To:</b> - <b>Címzett:</b> - - - - (yours, label: - (tiéd, címke: - - - - (yours) - (tiéd) - - - - - - - <b>Credit:</b> - <b>Jóváírás</b> - - - - (%1 matures in %2 more blocks) - (%1, %2 múlva készül el) - - - - (not accepted) - (elutasítva) - - - - - - <b>Debit:</b> - <b>Terhelés</b> - - - - <b>Transaction fee:</b> - <b>Tranzakciós díj:</b> - - - - <b>Net amount:</b> - <b>Nettó összeg:</b> - - - - Message: - Üzenet: - - - - Comment: - Megjegyzés: - - - - Transaction ID: + + Source - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + + Generated + Legenerálva + + + + + From + Űrlap + + + + + + To + Címzett + + + + + own address + + + + + label + címke + + + + + + + + Credit + Jóváírás + + + + matures in %n more block(s) + + + + + not accepted + elutasítva + + + + + + + Debit + Terhelés + + + + Transaction fee + Tranzakciós díj + + + + Net amount + Nettó összeg + + + + Message + Üzenet + + + + Comment + Megjegyzés + + + + Transaction ID + + + + + Generated coins must mature 120 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. A frissen generált érméket csak 120 blokkal később tudod elkölteni. Ez a blokk nyomban szétküldésre került a hálózatba, amint legeneráltad, hogy hozzáadhassák a blokklánchoz. Ha nem kerül be a láncba, úgy az állapota "elutasítva"-ra módosul, és nem költheted el az érméket. Ez akkor következhet be időnként, ha egy másik csomópont mindössze néhány másodperc különbséggel generált le egy blokkot a tiédhez képest. + + + Debug information + + + + + Transaction + Tranzakció + + + + Inputs + + + + + Amount + Összeg + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + , még nem sikerült elküldeni. + + + + Open for %n more block(s) + + + + + unknown + ismeretlen + TransactionDescDialog - + Transaction details Tranzakció részletei - + This pane shows a detailed description of the transaction Ez a mező a tranzakció részleteit mutatja @@ -1571,117 +1849,117 @@ Cím: %4 TransactionTableModel - + Date Dátum - + Type Típus - + Address Cím - + Amount Összeg - - Open for %n block(s) - %n blokkra megnyitva%n blokkra megnyitva + + Open for %n more block(s) + - + Open until %1 %1-ig megnyitva - + Offline (%1 confirmations) Offline (%1 megerősítés) - + Unconfirmed (%1 of %2 confirmations) Megerősítetlen (%1 %2 megerősítésből) - + Confirmed (%1 confirmations) Megerősítve (%1 megerősítés) - - Mined balance will be available in %n more blocks - %n blokk múlva lesz elérhető a bányászott egyenleg.%n blokk múlva lesz elérhető a bányászott egyenleg. + + Mined balance will be available when it matures in %n more block(s) + - + This block was not received by any other nodes and will probably not be accepted! Ezt a blokkot egyetlen másik csomópont sem kapta meg, így valószínűleg nem lesz elfogadva! - + Generated but not accepted Legenerálva, de még el nem fogadva. - + Received with Erre a címre - + Received from - + Erről az - + Sent to Erre a címre - + Payment to yourself Magadnak kifizetve - + Mined Kibányászva - + (n/a) (nincs) - + Transaction status. Hover over this field to show number of confirmations. Tranzakció állapota. Húzd ide a kurzort, hogy lásd a megerősítések számát. - + Date and time that the transaction was received. Tranzakció fogadásának dátuma és időpontja. - + Type of transaction. Tranzakció típusa. - + Destination address of transaction. A tranzakció címzettjének címe. - + Amount removed from or added to balance. Az egyenleghez jóváírt vagy ráterhelt összeg. @@ -1689,846 +1967,984 @@ Cím: %4 TransactionView - - + + All Mind - + Today Mai - + This week Ezen a héten - + This month Ebben a hónapban - + Last month Múlt hónapban - + This year Ebben az évben - + Range... Tartomány ... - + Received with Erre a címre - + Sent to Erre a címre - + To yourself Magadnak - + Mined Kibányászva - + Other Más - + Enter address or label to search Írd be a keresendő címet vagy címkét - + Min amount Minimális összeg - + Copy address Cím másolása - + Copy label Címke másolása - + Copy amount + Összeg másolása + + + + Copy transaction ID - + Edit label Címke szerkesztése - + Show transaction details - + Tranzakciós részletek megjelenítése - + Export Transaction Data Tranzakció adatainak exportálása - + Comma separated file (*.csv) Vesszővel elválasztott fájl (*.csv) - + Confirmed Megerősítve - + Date Dátum - + Type Típus - + Label Címke - + Address Cím - + Amount Összeg - + ID Azonosító - + Error exporting Hiba lépett fel exportálás közben - + Could not write to file %1. %1 fájlba való kiírás sikertelen. - + Range: Tartomány: - + to meddig - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - A kiválasztott cím másolása a vágólapra - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Küldés ... + + Send Coins + Érmék küldése - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Kicsinyítés a tálcára az eszköztár helyett + + Export the data in the current tab to a file + Jelenlegi nézet exportálása fájlba - - Show only a tray icon after minimizing the window - Kicsinyítés után csak eszköztár-ikont mutass + + Backup Wallet + Biztonsági másolat készítése a Tárcáról - - M&inimize on close + + Wallet Data (*.dat) + Tárca fájl (*.dat) + + + + Backup Failed + Biztonsági másolat készítése sikertelen + + + + There was an error trying to save the wallet data to the new location. + Hiba lépett fel a Tárca másik helyre való mentése közben + + + + Backup Successful - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Az alkalmazásból való kilépés helyett az eszköztárba kicsinyíti az alkalmazást az ablak bezárásakor. Ez esetben az alkalmazás csak a Kilépés menüponttal zárható be. + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - Bitcoin verzió + + CasinoCoin version + CasinoCoin verzió - + Usage: Használat: - - Send command to -server or bitcoind - Parancs küldése a -serverhez vagy a bitcoindhez + + Send command to -server or casinocoind + Parancs küldése a -serverhez vagy a casinocoindhez - + List commands Parancsok kilistázása - + Get help for a command Segítség egy parancsról - + Options: Opciók - - Specify configuration file (default: bitcoin.conf) - Konfigurációs fájl (alapértelmezett: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Konfigurációs fájl (alapértelmezett: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - pid-fájl (alapértelmezett: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + pid-fájl (alapértelmezett: casinocoind.pid) - - Generate coins - Érmék generálása - - - - - Don't generate coins - Bitcoin-generálás leállítása - - - - + Specify data directory Adatkönyvtár - + Set database cache size in megabytes (default: 25) - + Az adatbázis gyorsítótár mérete megabájtban (alapértelmezés: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Csatlakozásokhoz figyelendő <port> (alapértelmezett: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - Csatlakozás időkerete (milliszekundumban) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + Maximálisan <n> számú kapcsolat fenntartása a peerekkel (alapértelmezés: 125) - - Connect only to the specified node - Csatlakozás csak a megadott csomóponthoz - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Kapcsolódás egy csomóponthoz a peerek címeinek megszerzése miatt, majd szétkapcsolás - + Specify your own public address - + Adja meg az Ön saját nyilvános címét - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Helytelenül viselkedő peerek leválasztási határértéke (alapértelmezés: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Helytelenül viselkedő peerek kizárási ideje másodpercben (alapértelmezés: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + JSON-RPC csatlakozásokhoz figyelendő <port> (alapértelmezett: 47970 or testnet: 17970) - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - - - - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Parancssoros és JSON-RPC parancsok elfogadása - + Run in the background as a daemon and accept commands Háttérben futtatás daemonként és parancsok elfogadása - + Use the test network Teszthálózat használata - - Output extra debugging information + + Accept connections from outside (default: 1 if no -proxy or -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Figyelem: a -paytxfee nagyon magas. Ennyi tranzakciós díjat fogsz fizetni, ha elküldöd a tranzakciót. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Figyelem: Ellenőrizd, hogy helyesen van-e beállítva a gépeden a dátum és az idő. A CasinoCoin nem fog megfelelően működni, ha rosszul van beállítvaaz órád. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + Csatlakozás csak a megadott csomóponthoz + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Érvénytelen -tor cím: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + Csak blokklánccal egyező beépített ellenőrző pontok elfogadása (alapértelmezés: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + Prepend debug output with timestamp + Időbélyeges hibakeresési kimenet hozzáadása az elejéhez + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL-opciók: (lásd a CasinoCoin Wiki SSL-beállítási instrukcióit) + + + + Select the version of socks proxy to use (4-5, default: 5) - + Send trace/debug info to console instead of debug.log file - + trace/debug információ küldése a konzolra a debog.log fájl helyett - + Send trace/debug info to debugger + trace/debug információ küldése a debuggerre + + + + Set maximum block size in bytes (default: 250000) - + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Csatlakozás időkerete milliszekundumban (alapértelmezett: 5000) + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + Username for JSON-RPC connections Felhasználói név JSON-RPC csatlakozásokhoz - + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + Password for JSON-RPC connections Jelszó JSON-RPC csatlakozásokhoz - - Listen for JSON-RPC connections on <port> (default: 8332) - JSON-RPC csatlakozásokhoz figyelendő <port> (alapértelmezett: 8332) - - - - + Allow JSON-RPC connections from specified IP address JSON-RPC csatlakozások engedélyezése meghatározott IP-címről - + Send commands to node running on <ip> (default: 127.0.0.1) Parancsok küldése <ip> címen működő csomóponthoz (alapértelmezett: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Parancs, amit akkor hajt végre, amikor a legjobb blokk megváltozik (%s a cmd-ban lecserélődik a blokk hash-re) - + Upgrade wallet to latest format - + A Tárca frissítése a legfrissebb formátumra - + Set key pool size to <n> (default: 100) Kulcskarika mérete <n> (alapértelmezett: 100) - + Rescan the block chain for missing wallet transactions Blokklánc újraszkennelése hiányzó tárca-tranzakciók után - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL-opciók: (lásd a Bitcoin Wiki SSL-beállítási instrukcióit) - - - - + Use OpenSSL (https) for JSON-RPC connections OpenSSL (https) használata JSON-RPC csatalkozásokhoz - + Server certificate file (default: server.cert) Szervertanúsítvány-fájl (alapértelmezett: server.cert) - + Server private key (default: server.pem) Szerver titkos kulcsa (alapértelmezett: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Elfogadható rejtjelkulcsok (alapértelmezett: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH ) - - Warning: Disk space is low - - - - + This help message Ez a súgó-üzenet - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Az %s adatkönyvtár nem zárható. A Bitcoin valószínűleg fut már. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + A %s nem elérhető ezen a gépen (bind returned error %d, %s) - + Connect through socks proxy - + Csatlakozás SOCKS proxyn keresztül - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + DNS-kikeresés engedélyezése az addnode-nál és a connect-nél - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Címek betöltése... - - Error loading blkindex.dat - - - - + Error loading wallet.dat: Wallet corrupted - + Hiba a wallet.dat betöltése közben: meghibásodott tárca - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Hiba a wallet.dat betöltése közben: ehhez a tárcához újabb verziójú CasinoCoin-kliens szükséges - - Wallet needed to be rewritten: restart Bitcoin to complete - + + Wallet needed to be rewritten: restart CasinoCoin to complete + A Tárca újraírása szükséges: Indítsa újra a teljesen a CasinoCoin-t - + Error loading wallet.dat - + Hiba az wallet.dat betöltése közben - + Invalid -proxy address: '%s' - + Érvénytelen -proxy cím: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Ismeretlen hálózat lett megadva -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Ismeretlen -socks proxy kérése: %i - + Cannot resolve -bind address: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Étvénytelen -paytxfee=<összeg> összeg: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Hiba: nem sikerült létrehozni a tranzakciót - - - - Sending... - Küldés... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Hiba: a tranzakciót elutasították. Ezt az okozhatja, ha már elköltöttél valamennyi érmét a tárcádból - például ha a wallet.dat-od egy másolatát használtad, és így az elköltés csak abban lett jelölve, de itt nem. - - - + Invalid amount - + Étvénytelen összeg - + Insufficient funds - Nincs elég bitcoinod. + Nincs elég casinocoinod. - + Loading block index... Blokkindex betöltése... - + Add a node to connect to and attempt to keep the connection open - + Elérendő csomópont megadása and attempt to keep the connection open - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + A %s nem elérhető ezen a gépen. A CasinoCoin valószínűleg fut már. - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - + Fee per KB to add to transactions you send - + kB-onként felajánlandó díj az általad küldött tranzakciókhoz - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Tárca betöltése... - + Cannot downgrade wallet - + Nem sikerült a Tárca visszaállítása a korábbi verzióra - - Cannot initialize keypool - - - - + Cannot write default address - + Nem sikerült az alapértelmezett címet írni. - + Rescanning... Újraszkennelés... - + Done loading Betöltés befejezve. - + To use the %s option - + Használd a %s opciót - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - - - - + Error - + Hiba - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Figyelem: Ellenőrizd, hogy helyesen van-e beállítva a gépeden a dátum és az idő. A Bitcoin nem fog megfelelően működni, ha rosszul van beállítvaaz órád. + Be kell állítani rpcpassword=<password> a konfigurációs fájlban +%s +Ha a fájl nem létezik, hozd létre 'csak a felhasználó által olvasható' fájl engedéllyel \ No newline at end of file diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index 92d3b7c..194ebf7 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - Info su Bitcoin + + About CasinoCoin + Info su CasinoCoin - - <b>Bitcoin</b> version - Versione di <b>Bitcoin</b> + + <b>CasinoCoin</b> version + Versione di <b>CasinoCoin</b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Developers - + Questo è un software sperimentale. -Distribuito sotto la licenza software MIT/X11, vedi il file license.txt incluso oppure su http://www.opensource.org/licenses/mit-license.php. +Distribuito sotto la licenza software MIT/X11, vedi il file COPYING incluso oppure su http://www.opensource.org/licenses/mit-license.php. Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso del Toolkit OpenSSL (http://www.openssl.org/), software crittografico scritto da Eric Young (eay@cryptsoft.com) e software UPnP scritto da Thomas Bernard. + + + Copyright + Copyright + + + + The CasinoCoin developers + Sviluppatori di CasinoCoin + AddressBookPage - + Address Book Rubrica - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per tenere così traccia di chi ti sta pagando. - - - + Double-click to edit address or label Fai doppio click per modificare o cancellare l'etichetta - + Create a new address Crea un nuovo indirizzo - + Copy the currently selected address to the system clipboard Copia l'indirizzo attualmente selezionato nella clipboard - + &New Address - + &Nuovo indirizzo - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Questi sono i tuoi indirizzi CasinoCoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per tenere così traccia di chi ti sta pagando. + + + &Copy Address - + &Copia l'indirizzo - + Show &QR Code Mostra il codice &QR - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address Firma un messaggio per dimostrare di possedere questo indirizzo - - &Sign Message - &Firma il messaggio + + Sign &Message + Firma il &messaggio - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Cancella l'indirizzo attualmente selezionato dalla lista. Solo indirizzi d'invio possono essere cancellati. + + Delete the currently selected address from the list + Cancella l'indirizzo attualmente selezionato dalla lista - + + Export the data in the current tab to a file + Esporta i dati nella tabella corrente su un file + + + + &Export + &Esporta... + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verifica un messaggio per accertarsi che sia firmato con un indirizzo CasinoCoin specifico + + + + &Verify Message + &Verifica Messaggio + + + &Delete &Cancella - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Copia &l'etichetta - + &Edit - + &Modifica - + + Send &Coins + Invia &CasinoCoin + + + Export Address Book Data Esporta gli indirizzi della rubrica - + Comma separated file (*.csv) Testo CSV (*.csv) - + Error exporting Errore nell'esportazione - + Could not write to file %1. Impossibile scrivere sul file %1. @@ -126,17 +164,17 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso AddressTableModel - + Label Etichetta - + Address Indirizzo - + (no label) (nessuna etichetta) @@ -144,432 +182,460 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso AskPassphraseDialog - + Passphrase Dialog - + Finestra passphrase - + Enter passphrase Inserisci la passphrase - + New passphrase Nuova passphrase - + Repeat new passphrase Ripeti la passphrase - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Inserisci la passphrase per il portamonete.<br/>Per piacere usare unapassphrase di <b>10 o più caratteri casuali</b>, o <b>otto o più parole</b>. - + Encrypt wallet Cifra il portamonete - + This operation needs your wallet passphrase to unlock the wallet. Quest'operazione necessita della passphrase per sbloccare il portamonete. - + Unlock wallet Sblocca il portamonete - + This operation needs your wallet passphrase to decrypt the wallet. Quest'operazione necessita della passphrase per decifrare il portamonete, - + Decrypt wallet Decifra il portamonete - + Change passphrase Cambia la passphrase - + Enter the old and new passphrase to the wallet. Inserisci la vecchia e la nuova passphrase per il portamonete. - + Confirm wallet encryption Conferma la cifratura del portamonete - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ATTENZIONE: se si cifra il portamonete e si perde la frase d'ordine, <b>SI PERDERANNO TUTTI I PROPRI BITCOIN</b>! -Si è sicuri di voler cifrare il portamonete? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Attenzione: se si cifra il portamonete e si perde la frase d'ordine, <b>SI PERDERANNO TUTTI I PROPRI CASINOCOIN</b>! - - + + Are you sure you wish to encrypt your wallet? + Si è sicuri di voler cifrare il portamonete? + + + + 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. + IMPORTANTE: qualsiasi backup del portafoglio effettuato precedentemente dovrebbe essere sostituito con il file del portafoglio criptato appena generato. Per ragioni di sicurezza, i backup precedenti del file del portafoglio non criptato diventeranno inservibili non appena si inizi ad usare il nuovo portafoglio criptato. + + + + + Warning: The Caps Lock key is on! + Attenzione: tasto Blocco maiuscole attivo. + + + + Wallet encrypted Portamonete cifrato - - Bitcoin 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. - Bitcoin verrà ora chiuso per finire il processo di crittazione. Ricorda che criptare il tuo portamonete non può fornire una protezione totale contro furti causati da malware che dovessero infettare il tuo computer. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin verrà ora chiuso per finire il processo di crittazione. Ricorda che criptare il tuo portamonete non può fornire una protezione totale contro furti causati da malware che dovessero infettare il tuo computer. - - - Warning: The Caps Lock key is on. - Attenzione: tasto Blocco maiuscole attivo. - - - - - - + + + + Wallet encryption failed Cifratura del portamonete fallita - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Cifratura del portamonete fallita a causa di un errore interno. Il portamonete non è stato cifrato. - - + + The supplied passphrases do not match. Le passphrase inserite non corrispondono. - + Wallet unlock failed Sblocco del portamonete fallito - - - + + + The passphrase entered for the wallet decryption was incorrect. La passphrase inserita per la decifrazione del portamonete è errata. - + Wallet decryption failed Decifrazione del portamonete fallita - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Passphrase del portamonete modificata con successo. BitcoinGUI - - Bitcoin Wallet - Portamonete di bitcoin - - - + Sign &message... - + Firma il &messaggio... - - Show/Hide &Bitcoin - Mostra/Nascondi &Bitcoin - - - + Synchronizing with network... Sto sincronizzando con la rete... - + &Overview &Sintesi - + Show general overview of wallet Mostra lo stato generale del portamonete - + &Transactions &Transazioni - + Browse transaction history Cerca nelle transazioni - - &Address Book - &Rubrica - - - + Edit the list of stored addresses and labels Modifica la lista degli indirizzi salvati e delle etichette - - &Receive coins - &Ricevi monete - - - + Show the list of addresses for receiving payments Mostra la lista di indirizzi su cui ricevere pagamenti - - &Send coins - &Invia monete - - - - Prove you control an address - Dimostra di controllare un indirizzo - - - + E&xit &Esci - + Quit application Chiudi applicazione - - &About %1 - &Informazioni su %1 + + Show information about CasinoCoin + Mostra informazioni su CasinoCoin - - Show information about Bitcoin - Mostra informazioni su Bitcoin - - - + About &Qt Informazioni su &Qt - + Show information about Qt Mostra informazioni su Qt - + &Options... &Opzioni... - + &Encrypt Wallet... - + &Cifra il portamonete... - + &Backup Wallet... - + &Backup Portamonete... - + &Change Passphrase... - - - - - ~%n block(s) remaining - ~%n blocco rimanente~%n blocchi rimanenti + &Cambia la passphrase... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Scaricati %1 di %2 blocchi dello storico delle transazioni ( il %3% ) + + Importing blocks from disk... + Importa blocchi dal disco... - - &Export... - &Esporta... + + Reindexing blocks on disk... + Re-indicizzazione blocchi su disco... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Invia monete ad un indirizzo casinocoin - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Modifica configurazione opzioni per casinocoin - - Show or hide the Bitcoin window - Mostra o nascondi la finestra Bitcoin - - - - Export the data in the current tab to a file - Esporta i dati nella tabella corrente su un file - - - - Encrypt or decrypt wallet - Cifra o decifra il portamonete - - - + Backup wallet to another location Backup portamonete in un'altra locazione - + Change the passphrase used for wallet encryption Cambia la passphrase per la cifratura del portamonete - + &Debug window - + Finestra &Debug - + Open debugging and diagnostic console - + Apri la console di degugging e diagnostica - + &Verify message... - + &Verifica messaggio... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Portamonete + + + + &Send + &Spedisci + + + + &Receive + &Ricevi + + + + &Addresses + &Indirizzi + + + + &About CasinoCoin + &Info su CasinoCoin + + + + &Show / Hide + &Mostra/Nascondi + + + + Show or hide the main Window + Mostra o nascondi la Finestra principale + + + + Encrypt the private keys that belong to your wallet + Crittografa le chiavi private che appartengono al tuo portafoglio + + + + Sign messages with your CasinoCoin addresses to prove you own them + Firma i messaggi con il tuo indirizzo CasinoCoin per dimostrare di possederli + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verifica i messaggi per accertarsi che siano stati firmati con gli indirizzi CasinoCoin specificati + + + &File &File - + &Settings &Impostazioni - + &Help &Aiuto - + Tabs toolbar Barra degli strumenti "Tabs" - - Actions toolbar - Barra degli strumenti "Azioni" - - - - + + [testnet] [testnet] - - - Bitcoin client - Bitcoin client + + CasinoCoin client + CasinoCoin client - - %n active connection(s) to Bitcoin network - %n connessione attiva alla rete Bitcoin%n connessioni attive alla rete Bitcoin + + %n active connection(s) to CasinoCoin network + %n connessione attiva alla rete CasinoCoin%n connessioni attive alla rete CasinoCoin - - Downloaded %1 blocks of transaction history. - Scaricati %1 blocchi dello storico transazioni. - - - - %n second(s) ago - %n secondo fa%n secondi fa - - - - %n minute(s) ago - %n minuto fa%n minuti fa - - - - %n hour(s) ago - %n ora fa%n ore fa - - - - %n day(s) ago - %n giorno fa%n giorni fa + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + Processati %1 di %2 (circa) blocchi della cronologia transazioni. + + + + Processed %1 blocks of transaction history. + Processati %1 blocchi della cronologia transazioni. + + + + %n hour(s) + %n ora%n ore + + + + %n day(s) + %n giorno%n giorni + + + + %n week(s) + %n settimana%n settimane + + + + %1 behind + + + + + Last received block was generated %1 ago. + L'ultimo blocco ricevuto è stato generato %1 fa. + + + + Transactions after this will not yet be visible. + + + + + Error + Errore + + + + Warning + Attenzione + + + + Information + Informazione + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Questa transazione è superiore al limite di dimensione. È comunque possibile inviarla con una commissione di %1, che va ai nodi che processano la tua transazione e contribuisce a sostenere la rete. Vuoi pagare la commissione? + + + Up to date Aggiornato - + Catching up... In aggiornamento... - - Last received block was generated %1. - L'ultimo blocco ricevuto è stato generato %1 - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Questa transazione è superiore al limite di dimensione. È comunque possibile inviarla con una commissione di %1, che va ai nodi che processano la tua transazione e contribuisce a sostenere la rete. Vuoi pagare la commissione? - - - + Confirm transaction fee - + Conferma compenso transazione - + Sent transaction Transazione inviata - + Incoming transaction Transazione ricevuta - + Date: %1 Amount: %2 Type: %3 @@ -583,539 +649,486 @@ Indirizzo: %4 - + + + URI handling + Gestione URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + Impossibile interpretare l'URI! Ciò può essere causato da un indirizzo CasinoCoin invalido o da parametri URI non corretti. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Il portamonete è <b>cifrato</b> e attualmente <b>sbloccato</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Il portamonete è <b>cifrato</b> e attualmente <b>bloccato</b> - - Backup Wallet - Backup Portamonete - - - - Wallet Data (*.dat) - Dati Portamonete (*.dat) - - - - Backup Failed - Backup fallito - - - - There was an error trying to save the wallet data to the new location. - C'è stato un errore tentanto di salvare i dati del portamonete in un'altra locazione - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Riscontrato un errore irreversibile. CasinoCoin non può più continuare in sicurezza e verrà terminato. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Mostra - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Scegli l'unità di suddivisione di default per l'interfaccia e per l'invio di monete - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Avviso di rete EditAddressDialog - + Edit Address Modifica l'indirizzo - + &Label &Etichetta - + The label associated with this address book entry L'etichetta associata a questo indirizzo nella rubrica - + &Address &Indirizzo - + The address associated with this address book entry. This can only be modified for sending addresses. L'indirizzo associato a questa voce della rubrica. Si può modificare solo negli indirizzi di spedizione. - + New receiving address Nuovo indirizzo di ricezione - + New sending address Nuovo indirizzo d'invio - + Edit receiving address Modifica indirizzo di ricezione - + Edit sending address Modifica indirizzo d'invio - + The entered address "%1" is already in the address book. L'indirizzo inserito "%1" è già in rubrica. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + L'indirizzo inserito "%1" non è un indirizzo casinocoin valido. - + Could not unlock wallet. Impossibile sbloccare il portamonete. - + New key generation failed. Generazione della nuova chiave non riuscita. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versione - + Usage: Utilizzo: - - options - + + command-line options + opzioni riga di comando - + UI options - + UI opzioni - + Set language, for example "de_DE" (default: system locale) - + Imposta lingua, ad esempio "it_IT" (predefinita: lingua di sistema) - + Start minimized Parti in icona - + Show splash screen on startup (default: 1) Mostra finestra di presentazione all'avvio (default: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Opzioni + + + + &Main + &Principale + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Paga la &commissione - - Main - Principale + + Automatically start CasinoCoin after logging in to the system. + Avvia automaticamente CasinoCoin all'accensione del computer - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Commissione di transazione per kB; è opzionale e contribuisce ad assicurare che le transazioni siano elaborate velocemente. Le transazioni sono per la maggior parte da 1 kB. Commissione raccomandata 0,01. + + &Start CasinoCoin on system login + &Fai partire CasinoCoin all'avvio del sistema - - &Start Bitcoin on system login - + + Reset all client options to default. + Ripristina tutte le opzioni del client alle predefinite. - - Automatically start Bitcoin after logging in to the system - + + &Reset Options + &Ripristina Opzioni - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + Rete - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Puoi firmare messeggi con i tuoi indirizzi per dimostrare che sono tuoi. Fai attenzione a non firmare niente di vago, visto che gli attacchi di phishing potrebbero cercare di spingerti a mettere la tua firma su di loro. Firma solo dichiarazioni completamente dettagliate con cui sei d'accordo. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Apri automaticamente la porta del client CasinoCoin sul router. Questo funziona solo se il router supporta UPnP ed è abilitato. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - L'indirizzo per firmare il messaggio con (esempio 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Scegli l'indirizzo dalla rubrica - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Incollare l'indirizzo dagli appunti - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Inserisci qui il messaggio che vuoi firmare - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Clicca "Firma il messaggio" per ottenere la firma - - - - Sign a message to prove you own this address - Firma un messaggio per dimostrare di possedere questo indirizzo - - - - &Sign Message - &Firma il messaggio - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Inserisci un indirizzo Bitcoin (ad esempio 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Errore nel firmare - - - - %1 is not a valid address. - %1 non è un indirizzo valido. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - La chiave privata per %1 non è disponibile. - - - - Sign failed - Firma non riuscita - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Mappa le porte tramite l'&UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Apri automaticamente la porta del client Bitcoin sul router. Questo funziona solo se il router supporta UPnP ed è abilitato. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Connettiti alla rete Bitcon attraverso un proxy SOCKS (ad esempio quando ci si collega via Tor) - - &Connect through SOCKS4 proxy: - &Collegati tramite SOCKS4 proxy: + + &Connect through SOCKS proxy: + &Collegati tramite SOCKS proxy: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Connettiti alla rete Bitcon attraverso un proxy SOCKS4 (ad esempio quando ci si collega via Tor) - - - + Proxy &IP: - + &IP del proxy: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Indirizzo IP del proxy (ad esempio 127.0.0.1) - - Port of the proxy (e.g. 1234) - Porta del proxy (es. 1234) + + &Port: + &Porta: - - - OptionsDialog - - Options - Opzioni + + Port of the proxy (e.g. 9050) + Porta del proxy (es. 9050) + + + + SOCKS &Version: + SOCKS &Version: + + + + SOCKS version of the proxy (e.g. 5) + Versione SOCKS del proxy (es. 5) + + + + &Window + &Finestra + + + + Show only a tray icon after minimizing the window. + Mostra solo un'icona nel tray quando si minimizza la finestra + + + + &Minimize to the tray instead of the taskbar + &Minimizza sul tray invece che sulla barra delle applicazioni + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Riduci ad icona, invece di uscire dall'applicazione quando la finestra viene chiusa. Quando questa opzione è attivata, l'applicazione verrà chiusa solo dopo aver selezionato Esci nel menu. + + + + M&inimize on close + M&inimizza alla chiusura + + + + &Display + &Mostra + + + + User Interface &language: + &Lingua Interfaccia Utente: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + La lingua dell'interfaccia utente può essere impostata qui. L'impostazione avrà effetto dopo il riavvio di CasinoCoin. + + + + &Unit to show amounts in: + &Unità di misura degli importi in: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Scegli l'unità di suddivisione di default per l'interfaccia e per l'invio di monete + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Se mostrare l'indirizzo CasinoCoin nella transazione o meno. + + + + &Display addresses in transaction list + &Mostra gli indirizzi nella lista delle transazioni + + + + &OK + &OK + + + + &Cancel + &Cancella + + + + &Apply + &Applica + + + + default + default + + + + Confirm options reset + Conferma ripristino opzioni + + + + Some settings may require a client restart to take effect. + Alcune modifiche necessitano del riavvio del programma per essere salvate. + + + + Do you want to proceed? + Vuoi procedere? + + + + + Warning + Attenzione + + + + + This setting will take effect after restarting CasinoCoin. + L'impostazione avrà effetto dopo il riavvio di CasinoCoin. + + + + The supplied proxy address is invalid. + L'indirizzo proxy che hai fornito è invalido. OverviewPage - + Form Modulo - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Le informazioni visualizzate sono datate. Il tuo partafogli verrà sincronizzato automaticamente con il network CasinoCoin dopo che la connessione è stabilita, ma questo processo non può essere completato ora. - + Balance: Saldo - - Number of transactions: - Numero di transazioni: - - - + Unconfirmed: Non confermato: - + Wallet - + Portamonete - + + Immature: + Immaturo: + + + + Mined balance that has not yet matured + Importo scavato che non è ancora maturato + + + <b>Recent transactions</b> <b>Transazioni recenti</b> - + Your current balance Saldo attuale - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Totale delle transazioni in corso di conferma, che non sono ancora incluse nel saldo attuale - - Total number of transactions in wallet - Numero delle transazioni effettuate - - - - + + out of sync + fuori sincrono + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - + Codice QR di dialogo - - QR Code - Codice QR - - - + Request Payment Richiedi pagamento - + Amount: Importo: - - BTC - BTC - - - + Label: Etichetta: - + Message: Messaggio: - + &Save As... &Salva come... - + Error encoding URI into QR Code. - + Errore nella codifica URI nel codice QR - + + The entered amount is invalid, please check. + L'importo specificato non è valido, prego verificare. + + + Resulting URI too long, try to reduce the text for label / message. L'URI risulta troppo lungo, prova a ridurre il testo nell'etichetta / messaggio. - + Save QR Code - + Salva codice QR - + PNG Images (*.png) Immagini PNG (*.png) @@ -1123,453 +1136,713 @@ Indirizzo: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Nome del client - - - - - - - - - + + + + + + + + + + N/A - + N/D - + Client version - + Versione client - + &Information - + &Informazione - - Client - + + Using OpenSSL version + Versione OpenSSL in uso - + Startup time - + Tempo di avvio - + Network - + Rete - + Number of connections - + Numero connessioni - + On testnet - + Nel testnet - + Block chain - + Block chain - + Current number of blocks - + Numero attuale di blocchi - + Estimated total blocks - + Numero totale stimato di blocchi - + Last block time - + Ora dell blocco piu recente - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Apri - + + Command-line options + opzioni riga di comando + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Mostra il messaggio di aiuto di CasinoCoin-QT per avere la lista di tutte le opzioni della riga di comando di CasinoCoin. + + + + &Show + &Mostra + + + &Console - + &Console - + Build date + Data di creazione + + + + CasinoCoin - Debug window + CasinoCoin - Finestra debug + + + + CasinoCoin Core - + + Debug log file + File log del Debug + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Apri il file di log del debug di CasinoCoin dalla cartella attuale. Può richiedere alcuni secondi per file di log grandi. + + + Clear console - + Svuota console - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Benvenuto nella console RPC di CasinoCoin - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Usa le frecce direzionali per navigare la cronologia, and <b>Ctrl-L</b> per cancellarla. - + Type <b>help</b> for an overview of available commands. - + Scrivi <b>help</b> per un riassunto dei comandi disponibili SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Spedisci Bitcoin + Spedisci CasinoCoin - + Send to multiple recipients at once Spedisci a diversi beneficiari in una volta sola - - &Add Recipient - + + Add &Recipient + &Aggiungi beneficiario - + Remove all transaction fields Rimuovi tutti i campi della transazione - + Clear &All - + Cancella &tutto - + Balance: Saldo: - + 123.456 BTC 123,456 BTC - + Confirm the send action Conferma la spedizione - - &Send + + S&end &Spedisci - + <b>%1</b> to %2 (%3) <b>%1</b> to %2 (%3) - + Confirm send coins - Conferma la spedizione di bitcoin + Conferma la spedizione di casinocoin - + Are you sure you want to send %1? Si è sicuri di voler spedire %1? - + and e - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. L'indirizzo del beneficiario non è valido, per cortesia controlla. - + The amount to pay must be larger than 0. L'importo da pagare dev'essere maggiore di 0. - + The amount exceeds your balance. - + L'importo è superiore al saldo attuale - + The total exceeds your balance when the %1 transaction fee is included. - + Il totale è superiore al saldo attuale includendo la commissione %1. - + Duplicate address found, can only send to each address once per send operation. - + Trovato un indirizzo doppio, si può spedire solo una volta a ciascun indirizzo in una singola operazione. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Errore: Creazione transazione fallita! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Errore: la transazione è stata rifiutata. Ciò accade se alcuni casinocoin nel portamonete sono stati già spesi, ad esempio se è stata usata una copia del file wallet.dat e i casinocoin sono stati spesi dalla copia ma non segnati come spesi qui. SendCoinsEntry - + Form Modulo - + A&mount: &Importo: - + Pay &To: Paga &a: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + L'indirizzo del beneficiario a cui inviare il pagamento (ad esempio Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Inserisci un'etichetta per questo indirizzo, per aggiungerlo nella rubrica - + &Label: &Etichetta - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - L'indirizzo del beneficiario cui inviare il pagamento (ad esempio 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Scegli l'indirizzo dalla rubrica - + Alt+A Alt+A - + Paste address from clipboard Incollare l'indirizzo dagli appunti - + Alt+P Alt+P - + Remove this recipient Rimuovere questo beneficiario - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Inserisci un indirizzo Bitcoin (ad esempio 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inserisci un indirizzo CasinoCoin (ad esempio Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Firme - Firma / Verifica un messaggio + + + + &Sign Message + &Firma il messaggio + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Puoi firmare messeggi con i tuoi indirizzi per dimostrare che sono tuoi. Fai attenzione a non firmare niente di vago, visto che gli attacchi di phishing potrebbero cercare di spingerti a mettere la tua firma su di loro. Firma solo dichiarazioni completamente dettagliate con cui sei d'accordo. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inserisci un indirizzo CasinoCoin (ad esempio Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Scegli l'indirizzo dalla rubrica + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Incollare l'indirizzo dagli appunti + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Inserisci qui il messaggio che vuoi firmare + + + + Signature + Firma + + + + Copy the current signature to the system clipboard + Copia la firma corrente nella clipboard + + + + Sign the message to prove you own this CasinoCoin address + Firma un messaggio per dimostrare di possedere questo indirizzo + + + + Sign &Message + Firma &messaggio + + + + Reset all sign message fields + Reimposta tutti i campi della firma + + + + + Clear &All + Cancella &tutto + + + + &Verify Message + &Verifica Messaggio + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inserisci un indirizzo CasinoCoin (ad esempio Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verifica il messaggio per assicurarsi che sia stato firmato con l'indirizzo CasinoCoin specificato + + + + Verify &Message + &Verifica Messaggio + + + + Reset all verify message fields + Reimposta tutti i campi della verifica messaggio + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inserisci un indirizzo CasinoCoin (ad esempio Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Clicca "Firma il messaggio" per ottenere la firma + + + + Enter CasinoCoin signature + Inserisci firma CasinoCoin + + + + + The entered address is invalid. + L'indirizzo inserito non è valido. + + + + + + + Please check the address and try again. + Per favore controlla l'indirizzo e prova ancora + + + + + The entered address does not refer to a key. + L'indirizzo casinocoin inserito non è associato a nessuna chiave. + + + + Wallet unlock was cancelled. + Sblocco del portafoglio annullato. + + + + Private key for the entered address is not available. + La chiave privata per l'indirizzo inserito non è disponibile. + + + + Message signing failed. + Firma messaggio fallita. + + + + Message signed. + Messaggio firmato. + + + + The signature could not be decoded. + Non è stato possibile decodificare la firma. + + + + + Please check the signature and try again. + Per favore controlla la firma e prova ancora. + + + + The signature did not match the message digest. + La firma non corrisponde al sunto del messaggio. + + + + Message verification failed. + Verifica messaggio fallita. + + + + Message verified. + Messaggio verificato. + + + + SplashScreen + + + The CasinoCoin developers + Sviluppatori di CasinoCoin + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Aperto per %1 blocchi - - - + Open until %1 Aperto fino a %1 - - %1/offline? - %1/offline? + + %1/offline + %1/offline - + %1/unconfirmed %1/non confermato - + %1 confirmations %1 conferme - - <b>Status:</b> - <b>Stato:</b> + + Status + Stato + + + + , broadcast through %n node(s) + , trasmesso attraverso %n nodo, trasmesso attraverso %n nodi - + + Date + Data + + + + Source + Sorgente + + + + Generated + Generato + + + + + From + Da + + + + + + To + A + + + + + own address + proprio indirizzo + + + + label + etichetta + + + + + + + + Credit + Credito + + + + matures in %n more block(s) + matura in %n ulteriore bloccomatura in altri %n blocchi + + + + not accepted + non accettate + + + + + + + Debit + Debito + + + + Transaction fee + Tranzakciós díj + + + + Net amount + Importo netto + + + + Message + Messaggio + + + + Comment + Commento + + + + Transaction ID + ID della transazione + + + + Generated coins must mature 120 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. + Bisogna attendere 120 blocchi prima di spendere I casinocoin generati. Quando è stato generato questo blocco, è stato trasmesso alla rete per aggiungerlo alla catena di blocchi. Se non riesce a entrare nella catena, verrà modificato in "non accettato" e non sarà spendibile. Questo può accadere a volte, se un altro nodo genera un blocco entro pochi secondi del tuo. + + + + Debug information + Informazione di debug + + + + Transaction + Transazione + + + + Inputs + Input + + + + Amount + Importo + + + + true + vero + + + + false + falso + + + , has not been successfully broadcast yet , non è stato ancora trasmesso con successo - - - , broadcast through %1 node - , trasmesso attraverso %1 nodo + + + Open for %n more block(s) + Aperto per %n altro bloccoAperto per altri %n blocchi - - , broadcast through %1 nodes - , trasmesso attraverso %1 nodi - - - - <b>Date:</b> - <b>Data:</b> - - - - <b>Source:</b> Generated<br> - <b>Fonte:</b> Generato<br> - - - - - <b>From:</b> - <b>Da:</b> - - - + unknown sconosciuto - - - - - <b>To:</b> - <b>Per:</b> - - - - (yours, label: - (vostro, etichetta: - - - - (yours) - (vostro) - - - - - - - <b>Credit:</b> - <b>Credito:</b> - - - - (%1 matures in %2 more blocks) - (%1 matura in altri %2 blocchi) - - - - (not accepted) - (non accettate) - - - - - - <b>Debit:</b> - <b>Debito:</b> - - - - <b>Transaction fee:</b> - <b>Commissione:</b> - - - - <b>Net amount:</b> - <b>Importo netto:</b> - - - - Message: - Messaggio: - - - - Comment: - Commento: - - - - Transaction ID: - ID della transazione: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Bisogna attendere 120 blocchi prima di spendere I bitcoin generati. Quando è stato generato questo blocco, è stato trasmesso alla rete per aggiungerlo alla catena di blocchi. Se non riesce a entrare nella catena, verrà modificato in "non accettato" e non sarà spendibile. Questo può accadere a volte, se un altro nodo genera un blocco entro pochi secondi del tuo. - TransactionDescDialog - + Transaction details Dettagli sulla transazione - + This pane shows a detailed description of the transaction Questo pannello mostra una descrizione dettagliata della transazione @@ -1577,117 +1850,117 @@ Indirizzo: %4 TransactionTableModel - + Date Data - + Type Tipo - + Address Indirizzo - + Amount Importo - - Open for %n block(s) - Aperto per %n bloccoAperto per %n blocchi + + Open for %n more block(s) + Aperto per %n altro bloccoAperto per altri %n blocchi - + Open until %1 Aperto fino a %1 - + Offline (%1 confirmations) Offline (%1 conferme) - + Unconfirmed (%1 of %2 confirmations) Non confermati (%1 su %2 conferme) - + Confirmed (%1 confirmations) Confermato (%1 conferme) - - Mined balance will be available in %n more blocks - Il saldo generato sarà disponibile tra %n altro bloccoIl saldo generato sarà disponibile tra %n altri blocchi + + Mined balance will be available when it matures in %n more block(s) + Il saldo generato sarà disponibile quando maturerà in %n altro bloccoIl saldo generato sarà disponibile quando maturerà in altri %n blocchi - + This block was not received by any other nodes and will probably not be accepted! Questo blocco non è stato ricevuto da altri nodi e probabilmente non sarà accettato! - + Generated but not accepted Generati, ma non accettati - + Received with Ricevuto tramite - + Received from Ricevuto da - + Sent to Spedito a - + Payment to yourself Pagamento a te stesso - + Mined Ottenuto dal mining - + (n/a) (N / a) - + Transaction status. Hover over this field to show number of confirmations. Stato della transazione. Passare con il mouse su questo campo per vedere il numero di conferme. - + Date and time that the transaction was received. Data e ora in cui la transazione è stata ricevuta. - + Type of transaction. Tipo di transazione. - + Destination address of transaction. Indirizzo di destinazione della transazione. - + Amount removed from or added to balance. Importo rimosso o aggiunto al saldo. @@ -1695,846 +1968,983 @@ Indirizzo: %4 TransactionView - - + + All Tutti - + Today Oggi - + This week Questa settimana - + This month Questo mese - + Last month Il mese scorso - + This year Quest'anno - + Range... Intervallo... - + Received with Ricevuto tramite - + Sent to Spedito a - + To yourself A te - + Mined Ottenuto dal mining - + Other Altro - + Enter address or label to search Inserisci un indirizzo o un'etichetta da cercare - + Min amount Importo minimo - + Copy address Copia l'indirizzo - + Copy label Copia l'etichetta - + Copy amount Copia l'importo - + + Copy transaction ID + + + + Edit label Modifica l'etichetta - + Show transaction details - + Mostra i dettagli della transazione - + Export Transaction Data Esporta i dati della transazione - + Comma separated file (*.csv) Testo CSV (*.csv) - + Confirmed Confermato - + Date Data - + Type Tipo - + Label Etichetta - + Address Indirizzo - + Amount Importo - + ID ID - + Error exporting Errore nell'esportazione - + Could not write to file %1. Impossibile scrivere sul file %1. - + Range: Intervallo: - + to a - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copia l'indirizzo attualmente selezionato nella clipboard - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Invio... + + Send Coins + Spedisci CasinoCoin - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Minimizza sul tray invece che sulla barra delle applicazioni + + Export the data in the current tab to a file + Esporta i dati nella tabella corrente su un file - - Show only a tray icon after minimizing the window - Mostra solo un'icona nel tray quando si minimizza la finestra - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Riduci ad icona, invece di uscire dall'applicazione quando la finestra viene chiusa. Quando questa opzione è attivata, l'applicazione verrà chiusa solo dopo aver selezionato Esci nel menu. + + Wallet Data (*.dat) + + + + + Backup Failed + Backup fallito + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + Backup eseguito con successo + + + + The wallet data was successfully saved to the new location. + Il portafoglio è stato correttamente salvato nella nuova cartella. bitcoin-core - - Bitcoin version - Versione di Bitcoin + + CasinoCoin version + Versione di CasinoCoin - + Usage: Utilizzo: - - Send command to -server or bitcoind - Manda il comando a -server o bitcoind + + Send command to -server or casinocoind + Manda il comando a -server o casinocoind - + List commands Lista comandi - + Get help for a command Aiuto su un comando - + Options: Opzioni: - - Specify configuration file (default: bitcoin.conf) - Specifica il file di configurazione (di default: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Specifica il file di configurazione (di default: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Specifica il file pid (default: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Specifica il file pid (default: casinocoind.pid) - - Generate coins - Genera Bitcoin - - - - - Don't generate coins - Non generare Bitcoin - - - - + Specify data directory Specifica la cartella dati - + Set database cache size in megabytes (default: 25) Imposta la dimensione cache del database in megabyte (default: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Ascolta le connessioni JSON-RPC su <porta> (default: 47950 o testnet: 17950) - - Specify connection timeout (in milliseconds) - Specifica il timeout di connessione (in millisecondi) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Ascolta le connessioni JSON-RPC su <porta> (default: 8333 o testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Mantieni al massimo <n> connessioni ai peer (default: 125) - - Connect only to the specified node - Connetti solo al nodo specificato - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Connessione ad un nodo per ricevere l'indirizzo del peer, e disconnessione - + Specify your own public address - + Specifica il tuo indirizzo pubblico - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Soglia di disconnessione dei peer di cattiva qualità (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Numero di secondi di sospensione che i peer di cattiva qualità devono trascorrere prima di riconnettersi (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Buffer di ricezione massimo per connessione, <n>*1000 byte (default: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Errore riscontrato durante l'impostazione della porta RPC %u per l'ascolto su IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Buffer di invio massimo per connessione, <n>*1000 byte (default: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Attendi le connessioni JSON-RPC su <porta> (default: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Accetta da linea di comando e da comandi JSON-RPC - + Run in the background as a daemon and accept commands Esegui in background come demone e accetta i comandi - + Use the test network Utilizza la rete di prova - - Output extra debugging information - Produci informazioni extra utili al debug + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accetta connessioni dall'esterno (default: 1 se no -proxy o -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Errore riscontrato durante l'impostazione della porta RPC %u per l'ascolto su IPv6, tornando su IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Collega all'indirizzo indicato e resta sempre in ascolto su questo. Usa la notazione [host]:porta per l'IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Non è possibile ottenere i dati sulla cartella %s. Probabilmente CasinoCoin è già in esecuzione. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Errore: la transazione è stata rifiutata. Ciò accade se alcuni casinocoin nel portamonete sono stati già spesi, ad esempio se è stata usata una copia del file wallet.dat e i casinocoin sono stati spesi dalla copia ma non segnati come spesi qui. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Errore: questa transazione necessita di una commissione di almeno %s a causa del suo ammontare, della sua complessità, o dell'uso di fondi recentemente ricevuti! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Esegui comando quando una transazione del portafoglio cambia (%s in cmd è sostituito da TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Imposta dimensione massima delle transazioni ad alta priorità/bassa-tassa in bytes (predefinito: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Questa versione è una compilazione pre-rilascio - usala a tuo rischio - non utilizzarla per la generazione o per applicazioni di commercio + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Attenzione: -paytxfee è molto alta. Questa è la commissione che si paga quando si invia una transazione. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Attenzione: le transazioni mostrate potrebbero essere sbagliate! Potresti aver bisogno di aggiornare, o altri nodi ne hanno bisogno. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Attenzione: si prega di controllare che la data del computer e l'ora siano corrette. Se il vostro orologio è sbagliato CasinoCoin non funziona correttamente. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Attenzione: errore di lettura di wallet.dat! Tutte le chiave lette correttamente, ma i dati delle transazioni o le voci in rubrica potrebbero mancare o non essere corretti. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Attenzione: wallet.dat corrotto, dati salvati! Il wallet.dat originale salvato come wallet.{timestamp}.bak in %s; se il tuo bilancio o le transazioni non sono corrette dovresti ripristinare da un backup. + + + + Attempt to recover private keys from a corrupt wallet.dat + Tenta di recuperare le chiavi private da un wallet.dat corrotto + + + + Block creation options: + Opzioni creazione blocco: + + + + Connect only to the specified node(s) + Connetti solo al nodo specificato + + + + Corrupted block database detected + Rilevato database blocchi corrotto + + + + Discover own IP address (default: 1 when listening and no -externalip) + Scopri proprio indirizzo IP (default: 1 se in ascolto e no -externalip) + + + + Do you want to rebuild the block database now? + Vuoi ricostruire ora il database dei blocchi? + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + Errore caricamento database blocchi + + + + Error opening block database + Errore caricamento database blocchi + + + + Error: Disk space is low! + Errore: la spazio libero sul disco è poco! + + + + Error: Wallet locked, unable to create transaction! + Errore: portafoglio bloccato, impossibile creare la transazione! + + + + Error: system error: + Errore: errore di sistema: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Impossibile mettersi in ascolto su una porta. Usa -listen=0 se vuoi usare questa opzione. + + + + Failed to read block info + Lettura informazioni blocco fallita + + + + Failed to read block + Lettura blocco fallita + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + Scrittura informazioni blocco fallita + + + + Failed to write block + Scrittura blocco fallita + + + + Failed to write file info + Scrittura informazioni file fallita + + + + Failed to write to coin database + Scrittura nel database dei casinocoin fallita + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + Trova peer utilizzando la ricerca DNS (predefinito: 1 finché utilizzato -connect) + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + Quanti blocchi da controllare all'avvio (predefinito: 288, 0 = tutti) + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + Verifica blocchi... + + + + Verifying wallet... + Verifica portafoglio... + + + + Imports blocks from external blk000??.dat file + Importa blocchi da un file blk000??.dat esterno + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Informazione + + + + Invalid -tor address: '%s' + Indirizzo -tor non valido: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Buffer di ricezione massimo per connessione, <n>*1000 byte (default: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Buffer di invio massimo per connessione, <n>*1000 byte (default: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Connetti solo a nodi nella rete <net> (IPv4, IPv6 o Tor) + + + + Output extra debugging information. Implies all other -debug* options + Produci informazioni extra utili al debug. Implies all other -debug* options + + + + Output extra network debugging information + Genera informazioni extra utili al debug della rete + + + Prepend debug output with timestamp Anteponi all'output di debug una marca temporale - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opzioni SSL: (vedi il wiki di CasinoCoin per le istruzioni di configurazione SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Selezionare la versione del proxy socks da usare (4-5, default: 5) + + + Send trace/debug info to console instead of debug.log file Invia le informazioni di trace/debug alla console invece che al file debug.log - + Send trace/debug info to debugger Invia le informazioni di trace/debug al debugger - + + Set maximum block size in bytes (default: 250000) + Imposta dimensione massima del blocco in bytes (predefinito: 250000) + + + + Set minimum block size in bytes (default: 0) + Imposta dimensione minima del blocco in bytes (predefinito: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Riduci il file debug.log all'avvio del client (predefinito: 1 se non impostato -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Specifica il timeout di connessione in millisecondi (default: 5000) + + + + System error: + Errore di sistema: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Usa un proxy per raggiungere servizi nascosti di tor (predefinito: uguale a -proxy) + + + Username for JSON-RPC connections Nome utente per connessioni JSON-RPC - + + Warning + Attenzione + + + + Warning: This version is obsolete, upgrade required! + Attenzione: questa versione è obsoleta, aggiornamento necessario! + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + wallet.dat corrotto, salvataggio fallito + + + Password for JSON-RPC connections Password per connessioni JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - Attendi le connessioni JSON-RPC su <porta> (default: 8332) - - - - + Allow JSON-RPC connections from specified IP address Consenti connessioni JSON-RPC dall'indirizzo IP specificato - + Send commands to node running on <ip> (default: 127.0.0.1) Inviare comandi al nodo in esecuzione su <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Esegui il comando quando il miglior block cambia(%s nel cmd è sostituito dall'hash del blocco) - + Upgrade wallet to latest format Aggiorna il wallet all'ultimo formato - + Set key pool size to <n> (default: 100) Impostare la quantità di chiavi di riserva a <n> (default: 100) - + Rescan the block chain for missing wallet transactions Ripeti analisi della catena dei blocchi per cercare le transazioni mancanti dal portamonete - - How many blocks to check at startup (default: 2500, 0 = all) - Quanti blocchi da controllare all'avvio (default: 2500, 0 = tutti) - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Opzioni SSL: (vedi il wiki di Bitcoin per le istruzioni di configurazione SSL) - - - - + Use OpenSSL (https) for JSON-RPC connections Utilizzare OpenSSL (https) per le connessioni JSON-RPC - + Server certificate file (default: server.cert) File certificato del server (default: server.cert) - + Server private key (default: server.pem) Chiave privata del server (default: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrari accettabili (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Questo messaggio di aiuto - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Non è possibile ottenere i dati sulla directory %s. Probabilmente Bitcoin è già in esecuzione. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Impossibile collegarsi alla %s su questo computer (bind returned error %d, %s) - + Connect through socks proxy - + Connessione tramite socks proxy - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Consenti ricerche DNS per aggiungere nodi e collegare + - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Caricamento indirizzi... - - Error loading blkindex.dat - Errore caricamento blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Errore caricamento wallet.dat: Wallet corrotto - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Errore caricamento wallet.dat: il wallet richiede una versione nuova di Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Errore caricamento wallet.dat: il wallet richiede una versione nuova di CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Il portamonete deve essere riscritto: riavviare Bitcoin per completare + + Wallet needed to be rewritten: restart CasinoCoin to complete + Il portamonete deve essere riscritto: riavviare CasinoCoin per completare - + Error loading wallet.dat Errore caricamento wallet.dat - + Invalid -proxy address: '%s' - + Indirizzo -proxy non valido: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Rete sconosciuta specificata in -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Versione -socks proxy sconosciuta richiesta: %i - + Cannot resolve -bind address: '%s' - + Impossibile risolvere -bind address: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Impossibile risolvere indirizzo -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Importo non valido per -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Errore: creazione della transazione fallita - - - - Sending... - Invio... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Errore: la transazione è stata rifiutata. Ciò accade se alcuni bitcoin nel portamonete sono stati già spesi, ad esempio se è stata usata una copia del file wallet.dat e i bitcoin sono stati spesi dalla copia ma non segnati come spesi qui. - - - + Invalid amount - + Importo non valido - + Insufficient funds Fondi insufficienti - + Loading block index... Caricamento dell'indice del blocco... - + Add a node to connect to and attempt to keep the connection open - + Elérendő csomópont megadása and attempt to keep the connection open - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Impossibile collegarsi alla %s su questo computer. Probabilmente CasinoCoin è già in esecuzione. - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - Accetta connessioni da fuori (default: 1) - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - + Fee per KB to add to transactions you send Commissione per KB da aggiungere alle transazioni in uscita - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Caricamento portamonete... - + Cannot downgrade wallet - + Non è possibile retrocedere il wallet - - Cannot initialize keypool - - - - + Cannot write default address - + Non è possibile scrivere l'indirizzo di default - + Rescanning... Ripetere la scansione... - + Done loading Caricamento completato - + To use the %s option - + Per usare la opzione %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - - - - + Error Errore - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Attenzione: si prega di controllare che la data del computer e l'ora siano corrette. Se il vostro orologio è sbagliato Bitcoin non funziona correttamente. + Devi settare rpcpassword=<password> nel file di configurazione: %s Se il file non esiste, crealo con i permessi di amministratore \ No newline at end of file diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts new file mode 100644 index 0000000..e822ddc --- /dev/null +++ b/src/qt/locale/bitcoin_ja.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + CasinoCoinについて + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> バージョン + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + アドレス帳 + + + + Double-click to edit address or label + アドレスまたはラベルを編集するにはダブルクリック + + + + Create a new address + 新規アドレスの作成 + + + + Copy the currently selected address to the system clipboard + 現在選択されているアドレスをシステムのクリップボードにコピーする + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + 削除(&D) + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + アドレス帳データをエクスポートする + + + + Comma separated file (*.csv) + CSVファイル (*.csv) + + + + Error exporting + エクスポートエラー + + + + Could not write to file %1. + %1のファイルに書き込めませんでした。 + + + + AddressTableModel + + + Label + ラベル + + + + Address + アドレス + + + + (no label) + (ラベル無し) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + パスフレーズを入力 + + + + New passphrase + 新しいパスフレーズ + + + + Repeat new passphrase + 新しいパスフレーズをもう一度 + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + ウォレットの新しいパスフレーズを入力してください。<br/><b>8個以上の単語か10個以上のランダムな文字</b>を使ってください。 + + + + Encrypt wallet + ウォレットを暗号化する + + + + This operation needs your wallet passphrase to unlock the wallet. + この操作はウォレットをアンロックするためにパスフレーズが必要です。 + + + + Unlock wallet + ウォレットをアンロックする + + + + This operation needs your wallet passphrase to decrypt the wallet. + この操作はウォレットの暗号化解除のためにパスフレーズが必要です。 + + + + Decrypt wallet + ウォレットの暗号化を解除する + + + + Change passphrase + パスフレーズの変更 + + + + Enter the old and new passphrase to the wallet. + 新旧両方のパスフレーズを入力してください。 + + + + Confirm wallet encryption + ウォレットの暗号化を確認する + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + ウォレットは暗号化されました + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + ウォレットの暗号化に失敗しました + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + 内部エラーによりウォレットの暗号化が失敗しました。ウォレットは暗号化されませんでした。 + + + + + The supplied passphrases do not match. + パスフレーズが同じではありません。 + + + + Wallet unlock failed + ウォレットのアンロックに失敗しました + + + + + + The passphrase entered for the wallet decryption was incorrect. + ウォレットの暗号化解除のパスフレーズが正しくありません。 + + + + Wallet decryption failed + ウォレットの暗号化解除に失敗しました + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + ネットワークに同期中…… + + + + &Overview + 概要(&O) + + + + Show general overview of wallet + ウォレットの概要を見る + + + + &Transactions + 取引(&T) + + + + Browse transaction history + 取引履歴を閲覧 + + + + Edit the list of stored addresses and labels + 保存されたアドレスとラベルのリストを編集 + + + + Show the list of addresses for receiving payments + 支払い受け取り用アドレスのリストを見る + + + + E&xit + + + + + Quit application + アプリケーションを終了 + + + + Show information about CasinoCoin + CasinoCoinに関する情報を見る + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + オプション(&O) + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + ウォレット暗号化用パスフレーズの変更 + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + ファイル(&F) + + + + &Settings + 設定(&S) + + + + &Help + ヘルプ(&H) + + + + Tabs toolbar + タブツールバー + + + + + [testnet] + [testnet] + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + バージョンは最新です + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + 送金取引 + + + + Incoming transaction + 着金取引 + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + ウォレットは<b>暗号化され、アンロックされています</b> + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + ウォレットは<b>暗号化され、ロックされています</b> + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + アドレスの編集 + + + + &Label + ラベル(&L) + + + + The label associated with this address book entry + このアドレス帳の入った事と関係のレーベル + + + + &Address + &アドレス + + + + The address associated with this address book entry. This can only be modified for sending addresses. + アドレス帳の入った事の関係のアドレスです。これは遅れるのアドレスのためだけに編集出来ます。 + + + + New receiving address + 新しいの受け入れのアドレス + + + + New sending address + 新しいの送るのアドレス + + + + Edit receiving address + 受け入れのアドレスを編集する + + + + Edit sending address + 送るのアドレスを編集する + + + + The entered address "%1" is already in the address book. + 入ったのアドレス「%1」はもうアドレス帳にあります。 + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + 財布をアンロックするのは出来ませんでした。 + + + + New key generation failed. + 新しいのキーの生成は失敗しました。 + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + オプションズ + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + フォーム + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + 残高: + + + + Unconfirmed: + 未確認: + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + <b>最近の取引</b> + + + + Your current balance + 今の残高 + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + コインを送る + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + 残高: + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + フォーム + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + Helbidea + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + テキスト CSV (*.csv) + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + レーベル + + + + Address + Helbidea + + + + Amount + + + + + ID + + + + + Error exporting + エラー輸出 + + + + Could not write to file %1. + %1のファイルに書き込めませんでした。 + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + CasinoCoin Bertsio + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts new file mode 100644 index 0000000..409c11e --- /dev/null +++ b/src/qt/locale/bitcoin_la.ts @@ -0,0 +1,2937 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + Informatio de CasinoCoin + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versio + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + Hoc est experimentale programma. + +Distributum sub MIT/X11 licentia programmatum, vide comitantem plicam COPYING vel http://www.opensource.org/licenses/mit-license.php. + +Hoc productum continet programmata composita ab OpenSSL Project pro utendo in OpenSSL Toolkit (http://www.openssl.org/) et programmata cifrarum scripta ab Eric Young (eay@cryptsoft.com) et UPnP programmata scripta ab Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers + CasinoCoin curatores + + + + AddressBookPage + + + Address Book + Liber Inscriptionum + + + + Double-click to edit address or label + Dupliciter-clicca ut inscriptionem vel titulum mutes + + + + Create a new address + Crea novam inscriptionem + + + + Copy the currently selected address to the system clipboard + Copia inscriptionem iam selectam in latibulum systematis + + + + &New Address + &Nova Inscriptio + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Haec sunt inscriptiones CasinoCoin tuae pro accipendo pensitationes. Cupias variam ad quemque mittentem dare ut melius scias quem tibi pensare. + + + + &Copy Address + &Copia Inscriptionem + + + + Show &QR Code + Monstra codicem &QR + + + + Sign a message to prove you own a CasinoCoin address + Signa nuntium ut demonstres inscriptionem CasinoCoin a te possessam esse + + + + Sign &Message + Signa &Nuntium + + + + Delete the currently selected address from the list + Dele active selectam inscriptionem ex enumeratione + + + + Export the data in the current tab to a file + Exporta data in hac tabella in plicam + + + + &Export + &Exporta + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verifica nuntium ut cures signatum esse cum specificata inscriptione CasinoCoin + + + + &Verify Message + &Verifica Nuntium + + + + &Delete + &Dele + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Hae sunt inscriptiones mittendi pensitationes. Semper inspice quantitatem et inscriptionem accipiendi antequam nummos mittis. + + + + Copy &Label + Copia &Titulum + + + + &Edit + &Muta + + + + Send &Coins + Mitte &Nummos + + + + Export Address Book Data + Exporta Data Libri Inscriptionum + + + + Comma separated file (*.csv) + Comma Separata Plica (*.csv) + + + + Error exporting + Error exportandi + + + + Could not write to file %1. + Non potuisse scribere in plicam %1. + + + + AddressTableModel + + + Label + Titulus + + + + Address + Inscriptio + + + + (no label) + (nullus titulus) + + + + AskPassphraseDialog + + + Passphrase Dialog + Dialogus Tesserae + + + + Enter passphrase + Insere tesseram + + + + New passphrase + Nova tessera + + + + Repeat new passphrase + Itera novam tesseram + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Insero novam tesseram cassidili.<br/>Sodes tessera <b>10 pluriumve fortuitarum litterarum</b> utere aut <b>octo pluriumve verborum</b>. + + + + Encrypt wallet + Cifra cassidile + + + + This operation needs your wallet passphrase to unlock the wallet. + Huic operationi necesse est tessera cassidili tuo ut cassidile reseret. + + + + Unlock wallet + Resera cassidile + + + + This operation needs your wallet passphrase to decrypt the wallet. + Huic operationi necesse est tessera cassidili tuo ut cassidile decifret. + + + + Decrypt wallet + Decifra cassidile + + + + Change passphrase + Muta tesseram + + + + Enter the old and new passphrase to the wallet. + Insero veterem novamque tesseram cassidili. + + + + Confirm wallet encryption + Confirma cifrationem cassidilis + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Monitio: Si cassidile tuum cifras et tesseram amittis, tu <b>AMITTES OMNES TUOS NUMMOS BITOS</b>! + + + + Are you sure you wish to encrypt your wallet? + Certusne es te velle tuum cassidile cifrare? + + + + 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. + GRAVE: Oportet ulla prioria conservata quae fecisti de plica tui cassidilis reponi a nove generata cifrata plica cassidilis. Propter securitatem, prioria conservata de plica non cifrata cassidilis inutilia fiet simul atque incipis uti novo cifrato cassidili. + + + + + Warning: The Caps Lock key is on! + Monitio: Litterae ut capitales seratae sunt! + + + + + Wallet encrypted + Cassidile cifratum + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin iam desinet ut finiat actionem cifrandi. Memento cassidile cifrare non posse cuncte curare ne tui nummi clepantur ab malis programatibus in tuo computatro. + + + + + + + Wallet encryption failed + Cassidile cifrare abortum est + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Cassidile cifrare abortum est propter internum errorem. Tuum cassidile cifratum non est. + + + + + The supplied passphrases do not match. + Tesserae datae non eaedem sunt. + + + + Wallet unlock failed + Cassidile reserare abortum est. + + + + + + The passphrase entered for the wallet decryption was incorrect. + Tessera inserta pro cassidilis decifrando prava erat. + + + + Wallet decryption failed + Cassidile decifrare abortum est. + + + + Wallet passphrase was successfully changed. + Tessera cassidilis successa est in mutando. + + + + BitcoinGUI + + + Sign &message... + Signa &nuntium... + + + + Synchronizing with network... + Synchronizans cum rete... + + + + &Overview + &Summarium + + + + Show general overview of wallet + Monstra generale summarium cassidilis + + + + &Transactions + &Transactiones + + + + Browse transaction history + Inspicio historiam transactionum + + + + Edit the list of stored addresses and labels + Muta indicem salvatarum inscriptionum titulorumque + + + + Show the list of addresses for receiving payments + Monstra indicem inscriptionum quibus pensitationes acceptandae + + + + E&xit + E&xi + + + + Quit application + Exi applicatione + + + + Show information about CasinoCoin + Monstra informationem de CasinoCoin + + + + About &Qt + Informatio de &Qt + + + + Show information about Qt + Monstra informationem de Qt + + + + &Options... + &Optiones + + + + &Encrypt Wallet... + &Cifra Cassidile... + + + + &Backup Wallet... + &Conserva Cassidile... + + + + &Change Passphrase... + &Muta tesseram... + + + + Importing blocks from disk... + Importans frusta ab disco... + + + + Reindexing blocks on disk... + Recreans indicem frustorum in disco... + + + + Send coins to a CasinoCoin address + Mitte nummos ad inscriptionem CasinoCoin + + + + Modify configuration options for CasinoCoin + Muta configurationis optiones pro CasinoCoin + + + + Backup wallet to another location + Conserva cassidile in locum alium + + + + Change the passphrase used for wallet encryption + Muta tesseram utam pro cassidilis cifrando + + + + &Debug window + Fenestra &Debug + + + + Open debugging and diagnostic console + Aperi terminalem debug et diagnosticalem + + + + &Verify message... + &Verifica nuntium... + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Cassidile + + + + &Send + &Mitte + + + + &Receive + &Accipe + + + + &Addresses + &Inscriptiones + + + + &About CasinoCoin + &Informatio de CasinoCoin + + + + &Show / Hide + &Monstra/Occulta + + + + Show or hide the main Window + Monstra vel occulta Fenestram principem + + + + Encrypt the private keys that belong to your wallet + Cifra claves privatas quae cassidili tui sunt + + + + Sign messages with your CasinoCoin addresses to prove you own them + Signa nuntios cum tuis inscriptionibus CasinoCoin ut demonstres te eas possidere + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verifica nuntios ut certus sis eos signatos esse cum specificatis inscriptionibus CasinoCoin + + + + &File + &Plica + + + + &Settings + &Configuratio + + + + &Help + &Auxilium + + + + Tabs toolbar + Tabella instrumentorum "Tabs" + + + + + [testnet] + [testnet] + + + + CasinoCoin client + CasinoCoin cliens + + + + %n active connection(s) to CasinoCoin network + %n activa conexio ad rete CasinoCoin%n activae conexiones ad rete CasinoCoin + + + + No block source available... + Nulla fons frustorum absens... + + + + Processed %1 of %2 (estimated) blocks of transaction history. + Perfecta %1 de %2 (aestimato) frusta historiae transactionum. + + + + Processed %1 blocks of transaction history. + Processae %1 frusta historiae transactionum. + + + + %n hour(s) + %n hora%n horae + + + + %n day(s) + %n dies%n dies + + + + %n week(s) + %n hebdomas%n hebdomades + + + + %1 behind + %1 post + + + + Last received block was generated %1 ago. + Postremum acceptum frustum generatum est %1 abhinc. + + + + Transactions after this will not yet be visible. + Transactiones post hoc nondum visibiles erunt. + + + + Error + Error + + + + Warning + Monitio + + + + Information + Informatio + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Haec transactio maior est quam limen magnitudinis. Adhuc potes id mittere mercede %1, quae it nodis qui procedunt tuam transactionem et adiuvat sustinere rete. Visne mercedem solvere? + + + + Up to date + Recentissimo + + + + Catching up... + Persequens... + + + + Confirm transaction fee + Confirma mercedem transactionis + + + + Sent transaction + Transactio missa + + + + Incoming transaction + Transactio incipiens + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + Dies: %1 +Quantitas: %2 +Typus: %3 +Inscriptio: %4 + + + + + + URI handling + Tractatio URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI intellegi non posse! Huius causa possit inscriptionem CasinoCoin non validam aut URI parametra maleformata. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Cassidile <b>cifratum</b> est et iam nunc <b>reseratum</b> + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Cassidile <b>cifratum</b> est et iam nunc <b>seratum</b> + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Error fatalis accidit. CasinoCoin nondum pergere tute potest, et exibit. + + + + ClientModel + + + Network Alert + Monitio Retis + + + + EditAddressDialog + + + Edit Address + Muta Inscriptionem + + + + &Label + &Titulus + + + + The label associated with this address book entry + Titulus associatus huic insertione libri inscriptionum + + + + &Address + &Inscriptio + + + + The address associated with this address book entry. This can only be modified for sending addresses. + Titulus associatus huic insertione libri inscriptionum. Haec tantum mutari potest pro inscriptionibus mittendi + + + + New receiving address + Nova inscriptio accipiendi + + + + New sending address + Nova inscriptio mittendi + + + + Edit receiving address + Muta inscriptionem accipiendi + + + + Edit sending address + Muta inscriptionem mittendi + + + + The entered address "%1" is already in the address book. + Inserta inscriptio "%1" iam in libro inscriptionum est. + + + + The entered address "%1" is not a valid CasinoCoin address. + Inscriptio inserta "%1" non valida inscriptio CasinoCoin est. + + + + Could not unlock wallet. + Non potuisse cassidile reserare + + + + New key generation failed. + Generare novam clavem abortum est. + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + CasinoCoin-Qt + + + + version + versio + + + + Usage: + Usus: + + + + command-line options + Optiones mandati intiantis + + + + UI options + UI optiones + + + + Set language, for example "de_DE" (default: system locale) + Constitue linguam, exempli gratia "de_DE" (praedefinitum: lingua systematis) + + + + Start minimized + Incipe minifactum ut icon + + + + Show splash screen on startup (default: 1) + Monstra principem imaginem ad initium (praedefinitum: 1) + + + + OptionsDialog + + + Options + Optiones + + + + &Main + &Princeps + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optionalis merces transactionum singulis kB quae adiuvat curare tuas transactiones processas esse celeriter. Plurimi transactiones 1kB sunt. + + + + Pay transaction &fee + Solve &mercedem transactionis + + + + Automatically start CasinoCoin after logging in to the system. + Pelle CasinoCoin per se postquam in systema inire. + + + + &Start CasinoCoin on system login + &Pelle CasinoCoin cum inire systema + + + + Reset all client options to default. + Reconstitue omnes optiones clientis ad praedefinita. + + + + &Reset Options + &Reconstitue Optiones + + + + &Network + &Rete + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Aperi per se portam clientis CasinoCoin in itineratore. Hoc tantum effectivum est si itineratrum tuum supportat UPnP et id activum est. + + + + Map port using &UPnP + Designa portam utendo &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Connecte ad rete CasinoCoin per SOCKS vicarium (e.g. quando conectens per Tor). + + + + &Connect through SOCKS proxy: + &Conecte per SOCKS vicarium: + + + + Proxy &IP: + &IP vicarii: + + + + IP address of the proxy (e.g. 127.0.0.1) + Inscriptio IP vicarii (e.g. 127.0.0.1) + + + + &Port: + &Porta: + + + + Port of the proxy (e.g. 9050) + Porta vicarii (e.g. 9050) + + + + SOCKS &Version: + SOCKS &Versio: + + + + SOCKS version of the proxy (e.g. 5) + SOCKS versio vicarii (e.g. 5) + + + + &Window + &Fenestra + + + + Show only a tray icon after minimizing the window. + Monstra tantum iconem in tabella systematis postquam fenestram minifactam est. + + + + &Minimize to the tray instead of the taskbar + &Minifac in tabellam systematis potius quam applicationum + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minifac potius quam exire applicatione quando fenestra clausa sit. Si haec optio activa est, applicatio clausa erit tantum postquam selegeris Exi in menu. + + + + M&inimize on close + M&inifac ad claudendum + + + + &Display + &UI + + + + User Interface &language: + &Lingua monstranda utenti: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Lingua monstranda utenti hic constitui potest. Haec configuratio effectiva erit postquam CasinoCoin iterum initiatum erit. + + + + &Unit to show amounts in: + &Unita qua quantitates monstrare: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Selige praedefinitam unitam subdivisionis monstrare in interfacie et quando nummos mittere + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Num monstrare inscriptiones CasinoCoin in enumeratione transactionum. + + + + &Display addresses in transaction list + &Monstra inscriptiones in enumeratione transactionum + + + + &OK + &OK + + + + &Cancel + &Cancella + + + + &Apply + &Applica + + + + default + praedefinitum + + + + Confirm options reset + Confirma optionum reconstituere + + + + Some settings may require a client restart to take effect. + Aliis configurationibus fortasse necesse est clientem iterum initiare ut effectivae sint. + + + + Do you want to proceed? + Vis procedere? + + + + + Warning + Monitio + + + + + This setting will take effect after restarting CasinoCoin. + Haec configuratio effectiva erit postquam CasinoCoin iterum initiatum erit. + + + + The supplied proxy address is invalid. + Inscriptio vicarii tradita non valida est. + + + + OverviewPage + + + Form + Schema + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Monstrata informatio fortasse non recentissima est. Tuum cassidile per se synchronizat cum rete CasinoCoin postquam conexio constabilita est, sed hoc actio nondum perfecta est. + + + + Balance: + Pendendum: + + + + Unconfirmed: + Non confirmata: + + + + Wallet + Cassidile + + + + Immature: + Immatura: + + + + Mined balance that has not yet matured + Fossum pendendum quod nondum maturum est + + + + <b>Recent transactions</b> + <b>Recentes transactiones</b> + + + + Your current balance + Tuum pendendum iam nunc + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + Totali nummi transactionum quae adhuc confirmandae sunt, et nondum afficiunt pendendum + + + + + out of sync + non synchronizato + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + CasinoCoin incipere non potest: cliccare-ad-pensandum handler + + + + QRCodeDialog + + + QR Code Dialog + Dialogus QR Codicis + + + + Request Payment + Posce Pensitationem + + + + Amount: + Quantitas: + + + + Label: + Titulus: + + + + Message: + Nuntius: + + + + &Save As... + &Salva ut... + + + + Error encoding URI into QR Code. + Error codificandi URI in codicem QR. + + + + The entered amount is invalid, please check. + Inserta quantitas non est valida, sodes proba. + + + + Resulting URI too long, try to reduce the text for label / message. + Resultato URI nimis longo, conare minuere verba pro titulo / nuntio. + + + + Save QR Code + Salva codicem QR + + + + PNG Images (*.png) + Imagines PNG (*.png) + + + + RPCConsole + + + Client name + Nomen clientis + + + + + + + + + + + + + N/A + N/A + + + + Client version + Versio clientis + + + + &Information + &Informatio + + + + Using OpenSSL version + Utens OpenSSL versione + + + + Startup time + Tempus initiandi + + + + Network + Rete + + + + Number of connections + Numerus conexionum + + + + On testnet + In testnet + + + + Block chain + Catena frustorum + + + + Current number of blocks + Numerus frustorum iam nunc + + + + Estimated total blocks + Aestimatus totalis numerus frustorum + + + + Last block time + Hora postremi frusti + + + + &Open + &Aperi + + + + Command-line options + Optiones mandati initiantis + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Monstra nuntium auxilii CasinoCoin-Qt ut videas enumerationem possibilium optionum CasinoCoin mandati initiantis. + + + + &Show + &Monstra + + + + &Console + &Terminale + + + + Build date + Dies aedificandi + + + + CasinoCoin - Debug window + CasinoCoin - Fenestra debug + + + + CasinoCoin Core + CasinoCoin Nucleus + + + + Debug log file + Debug catalogi plica + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Aperi plicam catalogi de CasinoCoin debug ex activo indice datorum. Hoc possit pauca secunda pro plicis magnis catalogi. + + + + Clear console + Vacuefac terminale + + + + Welcome to the CasinoCoin RPC console. + Bene ventio in terminale RPC de CasinoCoin. + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Utere sagittis sursum deorsumque ut per historiam naviges, et <b>Ctrl+L</b> ut scrinium vacuefacias. + + + + Type <b>help</b> for an overview of available commands. + Scribe <b>help</b> pro summario possibilium mandatorum. + + + + SendCoinsDialog + + + + + + + + + + Send Coins + Mitte Nummos + + + + Send to multiple recipients at once + Mitte pluribus accipientibus simul + + + + Add &Recipient + Adde &Accipientem + + + + Remove all transaction fields + Remove omnes campos transactionis + + + + Clear &All + Vacuefac &Omnia + + + + Balance: + Pendendum: + + + + 123.456 BTC + 123.456 BTC + + + + Confirm the send action + Confirma actionem mittendi + + + + S&end + &Mitte + + + + <b>%1</b> to %2 (%3) + <b>%1</b> ad %2 (%3) + + + + Confirm send coins + Confirma mittendum nummorum + + + + Are you sure you want to send %1? + Certus es te velle mittere %1? + + + + and + et + + + + The recipient address is not valid, please recheck. + Inscriptio accipientis non est valida, sodes reproba. + + + + The amount to pay must be larger than 0. + Oportet quantitatem ad pensandum maiorem quam 0 esse. + + + + The amount exceeds your balance. + Quantitas est ultra quod habes. + + + + The total exceeds your balance when the %1 transaction fee is included. + Quantitas est ultra quod habes cum merces transactionis %1 includitur. + + + + Duplicate address found, can only send to each address once per send operation. + Geminata inscriptio inventa, tantum posse mittere ad quamque inscriptionem semel singulare operatione. + + + + Error: Transaction creation failed! + Error: Creare transactionem abortum est! + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Error: transactio reiecta est. Hoc fiat si alii nummorum in tuo cassidili iam soluti sunt, ut si usus es exemplar de wallet.dat et nummi soluti sunt in exemplari sed non hic notati ut soluti. + + + + SendCoinsEntry + + + Form + Schema + + + + A&mount: + &Quantitas: + + + + Pay &To: + Pensa &Ad: + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inscriptio cui mittere pensitationem (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book + Insero titulum huic inscriptioni ut eam in tuum librum inscriptionum addas. + + + + &Label: + &Titulus: + + + + Choose address from address book + Selige inscriptionem ex libro inscriptionum + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Conglutina inscriptionem ex latibulo + + + + Alt+P + Alt+P + + + + Remove this recipient + Remove hunc accipientem + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Insero inscriptionem CasinoCoin (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signationes - Signa / Verifica nuntium + + + + &Sign Message + &Signa Nuntium + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Potes nuntios signare inscriptionibus tuis ut demonstres te eas possidere. Cautus es non amibiguum signare, quia impetus phiscatorum conentur te fallere ut signes identitatem tuam ad eos. Solas signa sententias cuncte descriptas quibus convenis. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inscriptio qua signare nuntium (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Selige inscriptionem ex librum inscriptionum + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Glutina inscriptionem ex latibulo + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Insere hic nuntium quod vis signare + + + + Signature + Signatio + + + + Copy the current signature to the system clipboard + Copia signationem in latibulum systematis + + + + Sign the message to prove you own this CasinoCoin address + Signa nuntium ut demonstres hanc inscriptionem CasinoCoin a te possessa esse + + + + Sign &Message + Signa &Nuntium + + + + Reset all sign message fields + Reconstitue omnes campos signandi nuntii + + + + + Clear &All + Vacuefac &Omnia + + + + &Verify Message + &Verifica Nuntium + + + + Enter the signing 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. + Insere inscriptionem signantem, nuntium (cura ut copias intermissiones linearum, spatia, tabs, et cetera exacte) et signationem infra ut nuntium verifices. Cautus esto ne magis legas in signationem quam in nuntio signato ipso est, ut vites falli ab impetu homo-in-medio. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Inscriptio qua nuntius signatus est (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verifica nuntium ut cures signatum esse cum specifica inscriptione CasinoCoin + + + + Verify &Message + Verifica &Nuntium + + + + Reset all verify message fields + Reconstitue omnes campos verificandi nuntii + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Insere inscriptionem CasinoCoin (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Clicca "Signa Nuntium" ut signatio generetur + + + + Enter CasinoCoin signature + Insere signationem CasinoCoin + + + + + The entered address is invalid. + Inscriptio inserta non valida est. + + + + + + + Please check the address and try again. + Sodes inscriptionem proba et rursus conare. + + + + + The entered address does not refer to a key. + Inserta inscriptio clavem non refert. + + + + Wallet unlock was cancelled. + Cassidilis reserare cancellatum est. + + + + Private key for the entered address is not available. + Clavis privata absens est pro inserta inscriptione. + + + + Message signing failed. + Nuntium signare abortum est. + + + + Message signed. + Nuntius signatus. + + + + The signature could not be decoded. + Signatio decodificari non potuit. + + + + + Please check the signature and try again. + Sodes signationem proba et rursus conare. + + + + The signature did not match the message digest. + Signatio non convenit digesto nuntii + + + + Message verification failed. + Nuntium verificare abortum est. + + + + Message verified. + Nuntius verificatus. + + + + SplashScreen + + + The CasinoCoin developers + CasinoCoin curatores + + + + [testnet] + [testnet] + + + + TransactionDesc + + + Open until %1 + Apertum donec %1 + + + + %1/offline + %1/non conecto + + + + %1/unconfirmed + %1/non confirmata + + + + %1 confirmations + %1 confirmationes + + + + Status + Status + + + + , broadcast through %n node(s) + , disseminatum per %n nodo, disseminata per %n nodis + + + + Date + Dies + + + + Source + Fons + + + + Generated + Generatum + + + + + From + Ab + + + + + + To + Ad + + + + + own address + inscriptio propria + + + + label + titulus + + + + + + + + Credit + Creditum + + + + matures in %n more block(s) + maturum erit in %n plure frustomaturum erit in %n pluribus frustis + + + + not accepted + non acceptum + + + + + + + Debit + Debitum + + + + Transaction fee + Transactionis merces + + + + Net amount + Cuncta quantitas + + + + Message + Nuntius + + + + Comment + Annotatio + + + + Transaction ID + ID transactionis + + + + Generated coins must mature 120 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. + Nummis generatis necesse est maturitas 120 frustorum antequam illi transmitti possunt. Cum hoc frustum generavisti, disseminatum est ad rete ut addatur ad catenam frustorum. Si aboritur inire catenam, status eius mutabit in "non acceptum" et non transmittabile erit. Hoc interdum accidat si alter nodus frustum generat paucis secundis ante vel post tuum. + + + + Debug information + Informatio de debug + + + + Transaction + Transactio + + + + Inputs + Lectenda + + + + Amount + Quantitas + + + + true + verum + + + + false + falsum + + + + , has not been successfully broadcast yet + , nondum prospere disseminatum est + + + + Open for %n more block(s) + Aperi pro %n pluribus frustis + + + + unknown + ignotum + + + + TransactionDescDialog + + + Transaction details + Particularia transactionis + + + + This pane shows a detailed description of the transaction + Haec tabula monstrat descriptionem verbosam transactionis + + + + TransactionTableModel + + + Date + Dies + + + + Type + Typus + + + + Address + Inscriptio + + + + Amount + Quantitas + + + + Open for %n more block(s) + Aperi pro %n plure frustoAperi pro %n pluribus frustis + + + + Open until %1 + Apertum donec %1 + + + + Offline (%1 confirmations) + Non conectum (%1 confirmationes) + + + + Unconfirmed (%1 of %2 confirmations) + Non confirmatum (%1 de %2 confirmationibus) + + + + Confirmed (%1 confirmations) + Confirmatum (%1 confirmationes) + + + + Mined balance will be available when it matures in %n more block(s) + Fossum pendendum utibile erit quando id maturum est post %n plus frustumFossum pendendum utibile erit quando id maturum est post %n pluria frusta + + + + This block was not received by any other nodes and will probably not be accepted! + Hoc frustum non acceptum est ab ulla alia nodis et probabiliter non acceptum erit! + + + + Generated but not accepted + Generatum sed non acceptum + + + + Received with + Acceptum cum + + + + Received from + Acceptum ab + + + + Sent to + Missum ad + + + + Payment to yourself + Pensitatio ad te ipsum + + + + Mined + Fossa + + + + (n/a) + (n/a) + + + + Transaction status. Hover over this field to show number of confirmations. + Status transactionis. Supervola cum mure ut monstretur numerus confirmationum. + + + + Date and time that the transaction was received. + Dies et tempus quando transactio accepta est. + + + + Type of transaction. + Typus transactionis. + + + + Destination address of transaction. + Inscriptio destinationis transactionis. + + + + Amount removed from or added to balance. + Quantitas remota ex pendendo aut addita ei. + + + + TransactionView + + + + All + Omne + + + + Today + Hodie + + + + This week + Hac hebdomade + + + + This month + Hoc mense + + + + Last month + Postremo mense + + + + This year + Hoc anno + + + + Range... + Intervallum... + + + + Received with + Acceptum cum + + + + Sent to + Missum ad + + + + To yourself + Ad te ipsum + + + + Mined + Fossa + + + + Other + Alia + + + + Enter address or label to search + Insere inscriptionem vel titulum ut quaeras + + + + Min amount + Quantitas minima + + + + Copy address + Copia inscriptionem + + + + Copy label + Copia titulum + + + + Copy amount + Copia quantitatem + + + + Copy transaction ID + Copia transactionis ID + + + + Edit label + Muta titulum + + + + Show transaction details + Monstra particularia transactionis + + + + Export Transaction Data + Exporta Data Transactionum + + + + Comma separated file (*.csv) + Comma Separata Plica (*.csv) + + + + Confirmed + Confirmatum + + + + Date + Dies + + + + Type + Typus + + + + Label + Titulus + + + + Address + Inscriptio + + + + Amount + Quantitas + + + + ID + ID + + + + Error exporting + Error exportandi + + + + Could not write to file %1. + Non potuisse scribere ad plicam %1. + + + + Range: + Intervallum: + + + + to + ad + + + + WalletModel + + + Send Coins + Mitte Nummos + + + + WalletView + + + &Export + &Exporta + + + + Export the data in the current tab to a file + Exporta data in hac tabella in plicam + + + + Backup Wallet + Conserva cassidile + + + + Wallet Data (*.dat) + Data cassidilis (*.dat) + + + + Backup Failed + Conservare abortum est. + + + + There was an error trying to save the wallet data to the new location. + Error erat conante salvare data cassidilis ad novum locum. + + + + Backup Successful + Successum in conservando + + + + The wallet data was successfully saved to the new location. + Successum in salvando data cassidilis in novum locum. + + + + bitcoin-core + + + CasinoCoin version + Versio de CasinoCoin + + + + Usage: + Usus: + + + + Send command to -server or casinocoind + Mitte mandatum ad -server vel casinocoind + + + + List commands + Enumera mandata + + + + Get help for a command + Accipe auxilium pro mandato + + + + Options: + Optiones: + + + + Specify configuration file (default: casinocoin.conf) + Specifica configurationis plicam (praedefinitum: casinocoin.conf) + + + + Specify pid file (default: casinocoind.pid) + Specifica pid plicam (praedefinitum: casinocoin.pid) + + + + Specify data directory + Specifica indicem datorum + + + + Set database cache size in megabytes (default: 25) + Constitue magnitudinem databasis cache in megabytes (praedefinitum: 25) + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Ausculta pro conexionibus in <porta> (praedefinitum: 47950 vel testnet: 17950) + + + + Maintain at most <n> connections to peers (default: 125) + Manutene non plures quam <n> conexiones ad paria (praedefinitum: 125) + + + + Connect to a node to retrieve peer addresses, and disconnect + Conecta ad nodum acceptare inscriptiones parium, et disconecte + + + + Specify your own public address + Specifica tuam propriam publicam inscriptionem + + + + Threshold for disconnecting misbehaving peers (default: 100) + Limen pro disconectendo paria improba (praedefinitum: 100) + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Numerum secundorum prohibere ne paria improba reconectant (praedefinitum: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Error erat dum initians portam RPC %u pro auscultando in IPv4: %s + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Ausculta pro conexionibus JSON-RPC in <porta> (praedefinitum: 47970 vel testnet: 17970) + + + + Accept command line and JSON-RPC commands + Accipe terminalis et JSON-RPC mandata. + + + + Run in the background as a daemon and accept commands + Operare infere sicut daemon et mandata accipe + + + + Use the test network + Utere rete experimentale + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accipe conexiones externas (praedefinitum: 1 nisi -proxy neque -connect) + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, necesse est te rpcpassword constituere in plica configurationis: +%s +Hortatur te hanc fortuitam tesseram uti: +rpcuser=casinocoinrpc +rpcpassword=%s +(non est necesse te hanc tesseram meminisse) +Nomen usoris et tessera eadem esse NON POSSUNT. +Si plica non existit, eam crea cum permissionibus ut eius dominus tantum sinitur id legere. +Quoque hortatur alertnotify constituere ut tu notificetur de problematibus; +exempli gratia: alertnotify=echo %%s | mail -s "CasinoCoin Notificatio" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Error erat dum initians portam RPC %u pro auscultando in IPv6, labens retrorsum ad IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Conglutina ad inscriptionem datam et semper in eam ausculta. Utere [moderatrum]:porta notationem pro IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Non posse serare datorum indicem %s. CasinoCoin probabiliter iam operatur. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Error: Transactio eiecta est! Hoc possit accidere si alii nummorum in cassidili tuo iam soluti sint, ut si usus es exemplar de wallet.dat et nummi soluti sunt in exemplari sed non hic notati ut soluti. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Error: Huic transactioni necesse est merces saltem %s propter eius magnitudinem, complexitatem, vel usum recentum acceptorum nummorum! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Facere mandatum quotiescumque notificatio affinis accipitur (%s in mandato mutatur in nuntium) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Facere mandatum quotiescumque cassidilis transactio mutet (%s in mandato sbstituitur ab TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Constitue magnitudinem maximam transactionum magnae-prioritatis/parvae-mercedis in octetis/bytes (praedefinitum: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Hoc est prae-dimittum experimentala aedes - utere eo periculo tuo proprio - nolite utere fodendo vel applicationibus mercatoriis + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Monitio: -paytxfee constitutum valde magnum! Hoc est merces transactionis solves si mittis transactionem. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Monitio: Monstratae transactiones fortasse non recta sint! Forte oportet tibi progredere, an aliis nodis progredere. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Monitio: Sodes cura ut dies tempusque computatri tui recti sunt! Si horologium tuum pravum est, CasinoCoin non proprie fungetur. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Monitio: error legendo wallet.dat! Omnes claves recte lectae, sed data transactionum vel libri inscriptionum fortasse desint vel prava sint. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Monitio: wallet.data corrupta, data salvata! Originalis wallet.dat salvata ut wallet.{timestamp}.bak in %s; si pendendum tuum vel transactiones pravae sunt, oportet ab conservato restituere. + + + + Attempt to recover private keys from a corrupt wallet.dat + Conare recipere claves privatas de corrupto wallet.dat + + + + Block creation options: + Optiones creandi frustorum: + + + + Connect only to the specified node(s) + Conecte sole ad nodos specificatos (vel nodum specificatum) + + + + Corrupted block database detected + Corruptum databasum frustorum invenitur + + + + Discover own IP address (default: 1 when listening and no -externalip) + Discooperi propriam inscriptionem IP (praedefinitum: 1 quando auscultans et nullum -externalip) + + + + Do you want to rebuild the block database now? + Visne reficere databasum frustorum iam? + + + + Error initializing block database + Error initiando databasem frustorum + + + + Error initializing wallet database environment %s! + Error initiando systematem databasi cassidilis %s! + + + + Error loading block database + Error legendo frustorum databasem + + + + Error opening block database + Error aperiendo databasum frustorum + + + + Error: Disk space is low! + Error: Inopia spatii disci! + + + + Error: Wallet locked, unable to create transaction! + Error: Cassidile seratum, non posse transactionem creare! + + + + Error: system error: + Error: systematis error: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Non potuisse auscultare in ulla porta. Utere -listen=0 si hoc vis. + + + + Failed to read block info + Non potuisse informationem frusti legere + + + + Failed to read block + Non potuisse frustum legere + + + + Failed to sync block index + Synchronizare indicem frustorum abortum est + + + + Failed to write block index + Scribere indicem frustorum abortum est + + + + Failed to write block info + Scribere informationem abortum est + + + + Failed to write block + Scribere frustum abortum est + + + + Failed to write file info + Scribere informationem plicae abortum est + + + + Failed to write to coin database + Scribere databasem nummorum abortum est + + + + Failed to write transaction index + Scribere indicem transactionum abortum est + + + + Failed to write undo data + Scribere data pro cancellando mutationes abortum est + + + + Find peers using DNS lookup (default: 1 unless -connect) + Inveni paria utendo DNS quaerendo (praedefinitum: 1 nisi -connect) + + + + Generate coins (default: 0) + Genera nummos (praedefinitum: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Quot frusta proba ad initium (praedefinitum: 288, 0 = omnia) + + + + How thorough the block verification is (0-4, default: 3) + Quam perfecta frustorum verificatio est (0-4, praedefinitum: 3) + + + + Not enough file descriptors available. + Inopia descriptorum plicarum. + + + + Rebuild block chain index from current blk000??.dat files + Restituere indicem catenae frustorum ex activis plicis blk000??.dat + + + + Set the number of threads to service RPC calls (default: 4) + Constitue numerum filorum ad tractandum RPC postulationes (praedefinitum: 4) + + + + Verifying blocks... + Verificante frusta... + + + + Verifying wallet... + Verificante cassidilem... + + + + Imports blocks from external blk000??.dat file + Importat frusta ab externa plica blk000??.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Constitue numerum filorum verificationis scriptorum (Maximum 16, 0 = auto, <0 = tot corda libera erunt, praedefinitum: 0) + + + + Information + Informatio + + + + Invalid -tor address: '%s' + Inscriptio -tor non valida: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Quantitas non valida pro -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Quantitas non valida pro -mintxfee=<amount>: '%s' + + + + Maintain a full transaction index (default: 0) + Manutene completam indicem transactionum (praedefinitum: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maxima magnitudo memoriae pro datis accipendis singulis conexionibus, <n>*1000 octetis/bytes (praedefinitum: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maxima magnitudo memoriae pro datis mittendis singulis conexionibus, <n>*1000 octetis/bytes (praedefinitum: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Tantum accipe catenam frustorum convenientem internis lapidibus (praedefinitum: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Tantum conecte ad nodos in rete <net> (IPv4, IPv6 aut Tor) + + + + Output extra debugging information. Implies all other -debug* options + Exscribe additiciam informationem pro debug. Implicat omnes alias optiones -debug* + + + + Output extra network debugging information + Exscribe additiciam informationem pro retis debug. + + + + Prepend debug output with timestamp + Antepone pittacium temporis ante exscriptum de debug + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Optiones SSL: (vide vici de CasinoCoin pro instructionibus SSL configurationis) + + + + Select the version of socks proxy to use (4-5, default: 5) + Selige versionem socks vicarii utendam (4-5, praedefinitum: 5) + + + + Send trace/debug info to console instead of debug.log file + Mitte informationem vestigii/debug ad terminale potius quam plicam debug.log + + + + Send trace/debug info to debugger + Mitte informationem vestigii/debug ad debugger + + + + Set maximum block size in bytes (default: 250000) + Constitue maximam magnitudinem frusti in octetis/bytes (praedefinitum: 250000) + + + + Set minimum block size in bytes (default: 0) + Constitue minimam magnitudinem frusti in octetis/bytes (praedefinitum: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Diminue plicam debug.log ad initium clientis (praedefinitum: 1 nisi -debug) + + + + Signing transaction failed + Signandum transactionis abortum est + + + + Specify connection timeout in milliseconds (default: 5000) + Specifica tempumfati conexionis in millisecundis (praedefinitum: 5000) + + + + System error: + Systematis error: + + + + Transaction amount too small + Magnitudo transactionis nimis parva + + + + Transaction amounts must be positive + Necesse est magnitudines transactionum positivas esse. + + + + Transaction too large + Transactio nimis magna + + + + Use UPnP to map the listening port (default: 0) + Utere UPnP designare portam auscultandi (praedefinitum: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Utere UPnP designare portam auscultandi (praedefinitum: 1 quando auscultans) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Utere vicarium ut extendas ad tor servitia occulta (praedefinitum: idem ut -proxy) + + + + Username for JSON-RPC connections + Nomen utentis pro conexionibus JSON-RPC + + + + Warning + Monitio + + + + Warning: This version is obsolete, upgrade required! + Monitio: Haec versio obsoleta est, progressio postulata! + + + + You need to rebuild the databases using -reindex to change -txindex + Oportet recreare databases utendo -reindex ut mutes -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat corrupta, salvare abortum est + + + + Password for JSON-RPC connections + Tessera pro conexionibus JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Permitte conexionibus JSON-RPC ex inscriptione specificata + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Mitte mandata nodo operanti in <ip> (praedefinitum: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Pelle mandatum quando optissimum frustum mutat (%s in mandato substituitur ab hash frusti) + + + + Upgrade wallet to latest format + Progredere cassidile ad formam recentissimam + + + + Set key pool size to <n> (default: 100) + Constitue magnitudinem stagni clavium ad <n> (praedefinitum: 100) + + + + Rescan the block chain for missing wallet transactions + Iterum perlege catenam frustorum propter absentes cassidilis transactiones + + + + Use OpenSSL (https) for JSON-RPC connections + Utere OpenSSL (https) pro conexionibus JSON-RPC + + + + Server certificate file (default: server.cert) + Plica certificationis daemonis moderantis (praedefinitum: server.cert) + + + + Server private key (default: server.pem) + Clavis privata daemonis moderans (praedefinitum: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Acceptabiles cifrae (praedefinitum: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Hic nuntius auxilii + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Non posse conglutinare ad %s in hoc computatro (conglutinare redidit errorem %d, %s) + + + + Connect through socks proxy + Conecte per socks vicarium + + + + Allow DNS lookups for -addnode, -seednode and -connect + Permitte quaerenda DNS pro -addnode, -seednode, et -connect + + + + Loading addresses... + Legens inscriptiones... + + + + Error loading wallet.dat: Wallet corrupted + Error legendi wallet.dat: Cassidile corruptum + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Error legendi wallet.dat: Cassidili necesse est recentior versio CasinoCoin + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Cassidili necesse erat rescribi: Repelle CasinoCoin ut compleas + + + + Error loading wallet.dat + Error legendi wallet.dat + + + + Invalid -proxy address: '%s' + Inscriptio -proxy non valida: '%s' + + + + Unknown network specified in -onlynet: '%s' + Ignotum rete specificatum in -onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + Ignota -socks vicarii versio postulata: %i + + + + Cannot resolve -bind address: '%s' + Non posse resolvere -bind inscriptonem: '%s' + + + + Cannot resolve -externalip address: '%s' + Non posse resolvere -externalip inscriptionem: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Quantitas non valida pro -paytxfee=<quantitas>: '%s' + + + + Invalid amount + Quantitas non valida + + + + Insufficient funds + Inopia nummorum + + + + Loading block index... + Legens indicem frustorum... + + + + Add a node to connect to and attempt to keep the connection open + Adice nodum cui conectere et conare sustinere conexionem apertam + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Non posse conglutinare ad %s in hoc cumputatro. CasinoCoin probabiliter iam operatur. + + + + Fee per KB to add to transactions you send + Merces per KB addere ad transactiones tu mittas + + + + Loading wallet... + Legens cassidile... + + + + Cannot downgrade wallet + Non posse cassidile regredi + + + + Cannot write default address + Non posse scribere praedefinitam inscriptionem + + + + Rescanning... + Iterum perlegens... + + + + Done loading + Completo lengendi + + + + To use the %s option + Ut utaris optione %s + + + + Error + Error + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + Necesse est te rpcpassword=<tesseram> constituere in plica configurationum: +%s +Si plica non existat, crea eam cum permissionibus ut solus eius dominus eam legere sinatur. + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index f14b5ec..15cb0e8 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -3,123 +3,159 @@ AboutDialog - - About Bitcoin - Apie Bitcoiną + + About CasinoCoin + Apie CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versija + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versija - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Autorystės teisės© 2009-2012 Bitcoin Developers -DĖMESIO: programa eksperimentinė! + Tai eksperimentinė programa. -Platinama pagal licenziją MIT/X11, papildomą informaciją rasite faile license.txt arba dokumente pagal nuorodą: http://www.opensource.org/licenses/mit-license.php. +Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www.opensource.org/licenses/mit-license.php. -Šiame produkte yra projekto OpenSSL (http://www.openssl.org/), Eriko Jango (eay@cryptsoft.com) parašyti kriptografinės funkcijos ir algoritmai ir UPnP darbui skirtos funkcijos parašytos Tomo Bernardo. - +Šiame produkte yra OpenSSL projekto kuriamas OpenSSL Toolkit (http://www.openssl.org/), Eric Young parašyta kriptografinė programinė įranga bei Thomas Bernard sukurta UPnP programinė įranga. + + + + Copyright + + + + + The CasinoCoin developers + AddressBookPage - + Address Book Adresų knygelė - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Čia yra Jūsų adresai skirti mokėjimams gauti. Jūs galite skirtingiems žmonėms duoti skirtingus adresus. Tai Jums palengvins kontroliuoti mokėjimus bei padidins anonimiškumą. - - - - + Double-click to edit address or label - Tam, kad pakeisti ar redaguoti adresą arba žymę turite objektą dukart spragtelti pele. + Spragtelėkite, kad pakeistumėte adresą arba žymę - + Create a new address Sukurti naują adresą - + Copy the currently selected address to the system clipboard Kopijuoti esamą adresą į mainų atmintį - + &New Address - + &Naujas adresas - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Tai yra jūsų CasinoCoin adresai mokėjimų gavimui. Galite duoti skirtingus adresus atskiriems siuntėjams, kad galėtumėte sekti, kas jums moka. + + + &Copy Address - + &Kopijuoti adresą - + Show &QR Code Rodyti &QR kodą - - Sign a message to prove you own this address - Registruotis žinute įrodančia, kad turite šį adresą + + Sign a message to prove you own a CasinoCoin address + Pasirašykite žinutę, kad įrodytume, jog esate CasinoCoin adreso savininkas - - &Sign Message - &S Registruotis žinute + + Sign &Message + Registruoti praneši&mą - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Pašalinti iš sąrašo pažymėtą adresą(gali būti pašalinti tiktai adresų knygelės įrašai). + + Delete the currently selected address from the list + - + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Patikrinkite žinutę, jog įsitikintumėte, kad ją pasirašė nurodytas CasinoCoin adresas + + + + &Verify Message + &Tikrinti žinutę + + + &Delete - &D Pašalinti + &Trinti - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Kopijuoti ž&ymę - + &Edit + &Keisti + + + + Send &Coins - + Export Address Book Data Eksportuoti adresų knygelės duomenis - + Comma separated file (*.csv) Kableliais išskirtas failas (*.csv) - + Error exporting Eksportavimo klaida - + Could not write to file %1. Nepavyko įrašyti į failą %1. @@ -127,17 +163,17 @@ Platinama pagal licenziją MIT/X11, papildomą informaciją rasite faile license AddressTableModel - + Label Žymė - + Address Adresas - + (no label) (nėra žymės) @@ -145,432 +181,460 @@ Platinama pagal licenziją MIT/X11, papildomą informaciją rasite faile license AskPassphraseDialog - + Passphrase Dialog - + Slaptafrazės dialogas - + Enter passphrase - Įvesti slaptažodį + Įvesti slaptafrazę - + New passphrase - Naujas slaptažodis + Nauja slaptafrazė - + Repeat new passphrase - Pakartoti naują slaptažodį + Pakartokite naują slaptafrazę - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - Įveskite naują slaptažodį piniginei <br/> Prašome naudoti slaptažodį iš <b> 10 ar daugiau atsitiktinių simbolių </b> arba <b> aštuonių ar daugiau žodžių </b>. + Įveskite naują piniginės slaptafrazę.<br/>Prašome naudoti slaptafrazę iš <b> 10 ar daugiau atsitiktinių simbolių</b> arba <b>aštuonių ar daugiau žodžių</b>. - + Encrypt wallet Užšifruoti piniginę - + This operation needs your wallet passphrase to unlock the wallet. - Ši operacija reikalauja jūsų piniginės slaptažodžio jai atrakinti. + Ši operacija reikalauja jūsų piniginės slaptafrazės jai atrakinti. - + Unlock wallet Atrakinti piniginę - + This operation needs your wallet passphrase to decrypt the wallet. - Ši operacija reikalauja jūsų piniginės slaptažodžio jai iššifruoti. + Ši operacija reikalauja jūsų piniginės slaptafrazės jai iššifruoti. - + Decrypt wallet Iššifruoti piniginę - + Change passphrase - Pakeisti slaptažodį + Pakeisti slaptafrazę - + Enter the old and new passphrase to the wallet. - Įveskite seną ir naują piniginės slaptažodžius + Įveskite seną ir naują piniginės slaptafrazes. - + Confirm wallet encryption Patvirtinkite piniginės užšifravimą - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ĮSPĖJIMAS: Jei užšifruosite savo piniginę ir prarasite savo slaptažodį, Jūs <b> PRARASITE VISUS SAVO BITKOINUS, </b>! -Ar jūs tikrai norite užšifruoti savo piniginę? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Dėmesio: jei užšifruosite savo piniginę ir pamesite slaptafrazę, jūs<b>PRARASITE VISUS SAVO CASINOCOINUS</b>! - - + + Are you sure you wish to encrypt your wallet? + Ar tikrai norite šifruoti savo piniginę? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + Įspėjimas: įjungtas Caps Lock klavišas! + + + + Wallet encrypted Piniginė užšifruota - - Bitcoin 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. - Bitcoin dabar užsidarys šifravimo proceso pabaigai. Atminkite, kad piniginės šifravimas negali pilnai apsaugoti bitcoinų vagysčių kai tinkle esančios kenkėjiškos programos patenka į jūsų kompiuterį. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin dabar užsidarys šifravimo proceso pabaigai. Atminkite, kad piniginės šifravimas negali pilnai apsaugoti casinocoinų vagysčių kai tinkle esančios kenkėjiškos programos patenka į jūsų kompiuterį. - - - Warning: The Caps Lock key is on. - ĮSPĖJIMAS: Įjungtos didžiosios raidės - - - - - - + + + + Wallet encryption failed Nepavyko užšifruoti piniginę - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Dėl vidinės klaidos nepavyko užšifruoti piniginę.Piniginė neužšifruota. - - + + The supplied passphrases do not match. - Įvestas slaptažodis nesutampa + Įvestos slaptafrazės nesutampa. - + Wallet unlock failed Nepavyko atrakinti piniginę - - - + + + The passphrase entered for the wallet decryption was incorrect. - Neteisingai įvestas slaptažodis piniginės iššifravimui + Neteisingai įvestas slaptažodis piniginės iššifravimui. - + Wallet decryption failed - Nepavyko iššifruoti piniginę + Nepavyko iššifruoti piniginės - - Wallet passphrase was succesfully changed. - Sėkmingai pakeistas piniginės slaptažodis + + Wallet passphrase was successfully changed. + Piniginės slaptažodis sėkmingai pakeistas. BitcoinGUI - - Bitcoin Wallet - Bitkoinų piniginė - - - + Sign &message... - + Pasirašyti ži&nutę... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Sinchronizavimas su tinklu ... - + &Overview - &O Apžvalga + &Apžvalga - + Show general overview of wallet Rodyti piniginės bendrą apžvalgą - + &Transactions - &T Sandoriai + &Sandoriai - + Browse transaction history Apžvelgti sandorių istoriją - - &Address Book - &Adresų knygelė - - - + Edit the list of stored addresses and labels Redaguoti išsaugotus adresus bei žymes - - &Receive coins - &R Gautos monetos - - - + Show the list of addresses for receiving payments Parodyti adresų sąraša mokėjimams gauti - - &Send coins - &Siųsti monetas - - - - Prove you control an address - Įrodyti, kad jūs valdyti adresą - - - + E&xit - &x išėjimas + &Išeiti - + Quit application Išjungti programą - - &About %1 - &Apie %1 + + Show information about CasinoCoin + Rodyti informaciją apie CasinoCoin - - Show information about Bitcoin - Rodyti informaciją apie Bitkoiną - - - + About &Qt Apie &Qt - + Show information about Qt Rodyti informaciją apie Qt - + &Options... - &Opcijos... + &Parinktys... - + &Encrypt Wallet... - + &Užšifruoti piniginę... - + &Backup Wallet... - + &Backup piniginę... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Keisti slaptafrazę... - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... - &Eksportas... - - - - Send coins to a Bitcoin address + + Reindexing blocks on disk... - - Modify configuration options for Bitcoin - + + Send coins to a CasinoCoin address + Siųsti monetas CasinoCoin adresui - - Show or hide the Bitcoin window - + + Modify configuration options for CasinoCoin + Keisti casinocoin konfigūracijos galimybes - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - Užšifruoti ar iššifruoti piniginę - - - + Backup wallet to another location - + Daryti piniginės atsarginę kopiją - + Change the passphrase used for wallet encryption - Pakeisti slaptažodį naudojamą piniginės užšifravimui + Pakeisti slaptafrazę naudojamą piniginės užšifravimui - + &Debug window - + &Derinimo langas - + Open debugging and diagnostic console - + Atverti derinimo ir diagnostikos konsolę - + &Verify message... + &Tikrinti žinutę... + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Piniginė + + + + &Send - - Verify a message signature + + &Receive - + + &Addresses + + + + + &About CasinoCoin + &Apie CasinoCoin + + + + &Show / Hide + &Rodyti / Slėpti + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Failas - + &Settings - Nu&Statymai + &Nustatymai - + &Help - &H Pagelba + &Pagalba - + Tabs toolbar - Tabs įrankių juosta + Kortelių įrankinė - - Actions toolbar - Veiksmų įrankių juosta - - - - + + [testnet] [testavimotinklas] - - - Bitcoin client + + CasinoCoin client + CasinoCoin klientas + + + + %n active connection(s) to CasinoCoin network + %n CasinoCoin tinklo aktyvus ryšys%n CasinoCoin tinklo aktyvūs ryšiai%n CasinoCoin tinklo aktyvūs ryšiai + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. - - %n active connection(s) to Bitcoin network - %n Bitcoin tinklo aktyvus ryšys%n Bitcoin tinklo aktyvūs ryšiai%n Bitcoin tinklo aktyvūs ryšiai + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + - - Downloaded %1 blocks of transaction history. - Atsisiuntė %1 iš %2 sandorių istorijos blokų - - - - %n second(s) ago - Prieš %n sekundęPrieš %n sekundesPrieš %n sekundžių - - - - %n minute(s) ago - Prieš %n minutęPrieš %n minutesPrieš %n minutčių - - - - %n hour(s) ago - Prieš %n valandąPrieš %n valandasPrieš %n valandų - - - - %n day(s) ago - Prieš %n dienąPrieš %n dienasPrieš %n dienų + + %1 behind + - + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date - Iki šiol + Atnaujinta - + Catching up... - Gaudo... + Vejamasi... - - Last received block was generated %1. - Paskutinis gautas blokas buvo sukurtas %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Šis sandoris viršija leistiną dydį. Jūs galite įvykdyti jį papildomai sumokėję %1 mokesčių, kurie bus išsiųsti tais pačiais mazgais kuriais vyko sandoris ir padės palaikyti tinklą. Ar jūs norite apmokėti papildomą mokestį? - - - + Confirm transaction fee - + Patvirtinti sandorio mokestį - + Sent transaction Sandoris nusiųstas - + Incoming transaction Ateinantis sandoris - + Date: %1 Amount: %2 Type: %3 @@ -582,664 +646,632 @@ Tipas: %3 Adresas: %4 - + + + URI handling + URI apdorojimas + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Piniginė <b>užšifruota</b> ir šiuo metu <b>atrakinta</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Piniginė <b>užšifruota</b> ir šiuo metu <b>užrakinta</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Ekranas - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Rodomų ir siunčiamų monetų kiekio matavimo vienetai - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Tinklo įspėjimas EditAddressDialog - + Edit Address - Redaguoti adresą + Keisti adresą - + &Label - &L Žymė + Ž&ymė - + The label associated with this address book entry Žymė yra susieta su šios adresų knygelęs turiniu - + &Address &Adresas - + The address associated with this address book entry. This can only be modified for sending addresses. Adresas yra susietas su šios adresų knygelęs turiniu. Tai gali būti keičiama tik siuntimo adresams. - + New receiving address Naujas gavimo adresas - + New sending address Naujas siuntimo adresas - + Edit receiving address - Taisyti gavimo adresą + Keisti gavimo adresą - + Edit sending address - Taisyti siuntimo adresą + Keisti siuntimo adresą - + The entered address "%1" is already in the address book. - Įvestas adresas "%1"yra adresų knygelėje + Įvestas adresas „%1“ jau yra adresų knygelėje. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Įvestas adresas „%1“ nėra galiojantis CasinoCoin adresas. - + Could not unlock wallet. - Neįmanoma atrakinti piniginės + Nepavyko atrakinti piniginės. - + New key generation failed. - Naujas raktas nesukurtas + Naujo rakto generavimas nepavyko. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versija - + Usage: Naudojimas: - - options - + + command-line options + komandinės eilutės parametrai - + UI options - + Naudotoji sąsajos parametrai - + Set language, for example "de_DE" (default: system locale) - + Nustatyti kalbą, pavyzdžiui "lt_LT" (numatyta: sistemos kalba) - + Start minimized - Pradžia sumažinta + Paleisti sumažintą - + Show splash screen on startup (default: 1) - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - &f Mokėti sandorio mokestį - - - - Main - Pagrindinis - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Neprivaloma sandorio mokestis už KB, kuris padeda įsitikinti, kad jūsų sandoriai tvarkomi greitai. Daugelis sandorių yra tik 1KB dydžio. Rekomenduojamas 0,01 mokestis. - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Pasirinkite adresą iš adresų knygelės - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Įvesti adresą iš mainų atminties - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Įveskite pranešimą, kurį norite pasirašyti čia - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Spragtelėkite "Registruotis žinutę" tam, kad gauti parašą - - - - Sign a message to prove you own this address - Registruotis žinute įrodymuii, kad turite šį adresą - - - - &Sign Message - &S Registravimosi žinutė - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Įveskite bitkoinų adresą (pvz. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Klaida pasirašant - - - - %1 is not a valid address. - %1 tai negaliojantis adresas - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Privataus rakto %1 nėra - - - - Sign failed - Registravimas nepavyko - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - Prievado struktūra naudojant & UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automatiškai atidaryti Bitcoin kliento maršrutizatoriaus prievadą. Tai veikia tik tada, kai jūsų maršrutizatorius palaiko UPnP ir ji įjungta. - - - - &Connect through SOCKS4 proxy: - &C Jungtis per socks4 proxy: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Jungtis į Bitkoin tinklą per socks4 proxy (pvz. jungiantis per Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - IP adresas proxy (pvz. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Proxy prievadas (pvz. 1234) - - OptionsDialog - + Options - Opcijos + Parinktys + + + + &Main + &Pagrindinės + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + &Mokėti sandorio mokestį + + + + Automatically start CasinoCoin after logging in to the system. + Automatiškai paleisti Bitkoin programą įjungus sistemą. + + + + &Start CasinoCoin on system login + &Paleisti CasinoCoin programą su window sistemos paleidimu + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + &Tinklas + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automatiškai atidaryti CasinoCoin kliento prievadą maršrutizatoriuje. Tai veikia tik tada, kai jūsų maršrutizatorius palaiko UPnP ir ji įjungta. + + + + Map port using &UPnP + Persiųsti prievadą naudojant &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Jungtis į Bitkoin tinklą per socks proxy (pvz. jungiantis per Tor) + + + + &Connect through SOCKS proxy: + &Jungtis per SOCKS tarpinį serverį: + + + + Proxy &IP: + Tarpinio serverio &IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + Tarpinio serverio IP adresas (pvz. 127.0.0.1) + + + + &Port: + &Prievadas: + + + + Port of the proxy (e.g. 9050) + Tarpinio serverio preivadas (pvz, 9050) + + + + SOCKS &Version: + SOCKS &versija: + + + + SOCKS version of the proxy (e.g. 5) + Tarpinio serverio SOCKS versija (pvz., 5) + + + + &Window + &Langas + + + + Show only a tray icon after minimizing the window. + Po programos lango sumažinimo rodyti tik programos ikoną. + + + + &Minimize to the tray instead of the taskbar + &M sumažinti langą bet ne užduočių juostą + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Uždarant langą neuždaryti programos. Kai ši parinktis įjungta, programa bus uždaryta tik pasirinkus meniu komandą Baigti. + + + + M&inimize on close + &Sumažinti uždarant + + + + &Display + &Rodymas + + + + User Interface &language: + Naudotojo sąsajos &kalba: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Čia gali būti nustatyta naudotojo sąsajos kalba. Šis nustatymas įsigalios iš naujo paleidus CasinoCoin. + + + + &Unit to show amounts in: + &Vienetai, kuriais rodyti sumas: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Rodomų ir siunčiamų monetų kiekio matavimo vienetai + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + &Rodyti adresus sandorių sąraše + + + + &OK + &Gerai + + + + &Cancel + &Atšaukti + + + + &Apply + &Pritaikyti + + + + default + numatyta + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Įspėjimas + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + Nurodytas tarpinio serverio adresas negalioja. OverviewPage - + Form Forma - - - 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - + Balance: - Balansas + Balansas: - - Number of transactions: - Sandorių kiekis - - - + Unconfirmed: Nepatvirtinti: - + Wallet + Piniginė + + + + Immature: + Nepribrendę: + + + + Mined balance that has not yet matured - + <b>Recent transactions</b> - <b>Naujausi sandoris</b> + <b>Naujausi sandoriai</b> - + Your current balance Jūsų einamasis balansas - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Iš viso sandorių, įskaitant tuos kurie dar turi būti patvirtinti, ir jie dar nėra įskaičiuotii į einamosios sąskaitos balansą - - Total number of transactions in wallet - Bandras sandorių kiekis piniginėje - - - - + + out of sync + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + QRCodeDialog - + QR Code Dialog - + QR kodo dialogas - - QR Code - QR kodas - - - + Request Payment Prašau išmokėti - + Amount: Suma: - - BTC - BTC - - - + Label: Žymė: - + Message: Žinutė: - + &Save As... - &S išsaugoti kaip... + Į&rašyti kaip... - + Error encoding URI into QR Code. - + Klaida, koduojant URI į QR kodą. - + + The entered amount is invalid, please check. + Įvesta suma neteisinga, prašom patikrinti. + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + Įrašyti QR kodą - + PNG Images (*.png) - + PNG paveikslėliai (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Kliento pavadinimas - - - - - - - - - + + + + + + + + + + N/A - + nėra - + Client version - + Kliento versija - + &Information - + &Informacija - - Client - + + Using OpenSSL version + Naudojama OpenSSL versija - + Startup time - + Paleidimo laikas - + Network - + Tinklas - + Number of connections - + Prisijungimų kiekis - + On testnet - + Testnete - + Block chain - + Blokų grandinė - + Current number of blocks - + Dabartinis blokų skaičius - + Estimated total blocks - + Last block time - + Paskutinio bloko laikas - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open + &Atverti + + + + Command-line options + Komandinės eilutės parametrai + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. - + + &Show + &Rodyti + + + &Console - + &Konsolė - + Build date + Kompiliavimo data + + + + CasinoCoin - Debug window + CasinoCoin - Derinimo langas + + + + CasinoCoin Core + CasinoCoin branduolys + + + + Debug log file + Derinimo žurnalo failas + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. - + Clear console + Išvalyti konsolę + + + + Welcome to the CasinoCoin RPC console. - - Welcome to the Bitcoin RPC console. - - - - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1247,327 +1279,566 @@ Adresas: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Siųsti monetas - + Send to multiple recipients at once Siųsti keliems gavėjams vienu metu - - &Add Recipient - + + Add &Recipient + &A Pridėti gavėją - + Remove all transaction fields Pašalinti visus sandorio laukus - + Clear &All - + Išvalyti &viską - + Balance: Balansas: - + 123.456 BTC 123.456 BTC - + Confirm the send action Patvirtinti siuntimo veiksmą - - &Send + + S&end &Siųsti - + <b>%1</b> to %2 (%3) <b>%1</b> to %2 (%3) - + Confirm send coins - Patvirtinti siuntimui monetas + Patvirtinti monetų siuntimą - + Are you sure you want to send %1? - Ar esate įsitikinę, kad norite siųsti %1? + Ar tikrai norite siųsti %1? - + and - ir + ir - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Negaliojantis gavėjo adresas. Patikrinkite. - + The amount to pay must be larger than 0. - Apmokėjimo suma turi būti didesnė negu 0. + Apmokėjimo suma turi būti didesnė nei 0. - + The amount exceeds your balance. - + Suma viršija jūsų balansą. - + The total exceeds your balance when the %1 transaction fee is included. - + Jei pridedame sandorio mokestį %1 bendra suma viršija jūsų balansą. - + Duplicate address found, can only send to each address once per send operation. + Rastas adreso dublikatas. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Klaida: sandoris buvo atmestas.Tai gali įvykti, jei kai kurios monetos iš jūsų piniginėje jau buvo panaudotos, pvz. jei naudojote wallet.dat kopiją ir monetos buvo išleistos kopijoje, bet nepažymėtos kaip skirtos išleisti čia. SendCoinsEntry - + Form Forma - + A&mount: Su&ma: - + Pay &To: - Mokėti &T gavėjui: + Mokėti &gavėjui: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Įveskite žymę šiam adresui kad galėtumėte įtraukti ją į adresų knygelę - + &Label: - &L žymė: + Ž&ymė: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresas mokėjimo siuntimui (pvz. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Pasirinkite adresą iš adresų knygelės - + Alt+A Alt+A - + Paste address from clipboard Įvesti adresą iš mainų atminties - + Alt+P Alt+P - + Remove this recipient - Pašalinti šitą gavėją + Pašalinti šį gavėją - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Įveskite bitkoinų adresą (pvz. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Įveskite bitkoinų adresą (pvz. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Pasirašyti žinutę + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Įveskite bitkoinų adresą (pvz. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Pasirinkite adresą iš adresų knygelės + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Įvesti adresą iš mainų atminties + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Įveskite pranešimą, kurį norite pasirašyti čia + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + Registruotis žinute įrodymuii, kad turite šį adresą + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + Išvalyti &viską + + + + &Verify Message + &Patikrinti žinutę + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Įveskite bitkoinų adresą (pvz. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Patikrinkite žinutę, jog įsitikintumėte, kad ją pasirašė nurodytas CasinoCoin adresas + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Įveskite bitkoinų adresą (pvz. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Spragtelėkite "Registruotis žinutę" tam, kad gauti parašą + + + + Enter CasinoCoin signature + Įveskite CasinoCoin parašą + + + + + The entered address is invalid. + Įvestas adresas negalioja. + + + + + + + Please check the address and try again. + Prašom patikrinti adresą ir bandyti iš naujo. + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + Piniginės atrakinimas atšauktas. + + + + Private key for the entered address is not available. + + + + + Message signing failed. + Žinutės pasirašymas nepavyko. + + + + Message signed. + Žinutė pasirašyta. + + + + The signature could not be decoded. + Nepavyko iškoduoti parašo. + + + + + Please check the signature and try again. + Prašom patikrinti parašą ir bandyti iš naujo. + + + + The signature did not match the message digest. + Parašas neatitinka žinutės. + + + + Message verification failed. + Žinutės tikrinimas nepavyko. + + + + Message verified. + Žinutė patikrinta. + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testavimotinklas] TransactionDesc - - Open for %1 blocks - Atidaryta %1 blokams - - - + Open until %1 Atidaryta iki %1 - - %1/offline? - %1/atjungtas? + + %1/offline + %1/neprisijungęs - + %1/unconfirmed %1/nepatvirtintas - + %1 confirmations - %1 patvirtinimai + %1 patvirtinimų - - <b>Status:</b> - <b>Būsena:</b> + + Status + Būsena + + + + , broadcast through %n node(s) + - + + Date + Data + + + + Source + Šaltinis + + + + Generated + Sugeneruotas + + + + + From + Nuo + + + + + + To + Kam + + + + + own address + savo adresas + + + + label + žymė + + + + + + + + Credit + Kreditas + + + + matures in %n more block(s) + + + + + not accepted + nepriimta + + + + + + + Debit + Debitas + + + + Transaction fee + Sandorio mokestis + + + + Net amount + Neto suma + + + + Message + Žinutė + + + + Comment + Komentaras + + + + Transaction ID + Sandorio ID + + + + Generated coins must mature 120 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. + Išgautos monetos turi sulaukti 120 blokų, kol jos gali būti naudojamos. Kai sukūrėte šį bloką, jis buvo transliuojamas tinkle ir turėjo būti įtrauktas į blokų grandinę. Jei nepavyksta patekti į grandinę, bus pakeista į "nepriėmė", o ne "vartojamas". Tai kartais gali atsitikti, jei kitas mazgas per keletą sekundžių sukuria bloką po jūsų bloko. + + + + Debug information + Derinimo informacija + + + + Transaction + Sandoris + + + + Inputs + + + + + Amount + Suma + + + + true + tiesa + + + + false + netiesa + + + , has not been successfully broadcast yet , transliavimas dar nebuvo sėkmingas - - - , broadcast through %1 node - , transliuota per %1 mazgą + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , transliuota per %1 mazgus - - - - <b>Date:</b> - <b>Data:</b> - - - - <b>Source:</b> Generated<br> - <b>Šaltinis:</b> Sukurta<br> - - - - - <b>From:</b> - <b>Nuo:</b> - - - + unknown nežinomas - - - - - <b>To:</b> - <b>Skirta:</b> - - - - (yours, label: - (jūsų, žymė: - - - - (yours) - (jūsų) - - - - - - - <b>Credit:</b> - <b>Kreditas:</b> - - - - (%1 matures in %2 more blocks) - (%1 apmokėtinas %2 daugiau blokais) - - - - (not accepted) - (nepriimta) - - - - - - <b>Debit:</b> - <b>Debitas:</b> - - - - <b>Transaction fee:</b> - <b>Sandorio mokestis:</b> - - - - <b>Net amount:</b> - <b>Neto suma:</b> - - - - Message: - Žinutė: - - - - Comment: - Komentaras: - - - - Transaction ID: - Sandorio ID: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Išgautos monetos turi sulaukti 120 blokų, kol jos gali būti naudojamos. Kai sukūrėte šį bloką, jis buvo transliuojamas tinkle ir turėjo būti įtrauktas į blokų grandinę. Jei nepavyksta patekti į grandinę, bus pakeista į "nepriėmė", o ne "vartojamas". Tai kartais gali atsitikti, jei kitas mazgas per keletą sekundžių sukuria bloką po jūsų bloko. - TransactionDescDialog - + Transaction details - Sandorio išsami informacija + Sandorio detelės - + This pane shows a detailed description of the transaction Šis langas sandorio detalų aprašymą @@ -1575,117 +1846,117 @@ Adresas: %4 TransactionTableModel - + Date Data - + Type Tipas - + Address Adresas - + Amount Suma - - Open for %n block(s) - Atidaryta %n blokuiAtidaryta %n blokamsAtidaryta %n blokų + + Open for %n more block(s) + - + Open until %1 - Atidaryta kol %n + Atidaryta iki %1 - + Offline (%1 confirmations) Atjungta (%1 patvirtinimai) - + Unconfirmed (%1 of %2 confirmations) Nepatvirtintos (%1 iš %2 patvirtinimų) - + Confirmed (%1 confirmations) Patvirtinta (%1 patvirtinimai) - - Mined balance will be available in %n more blocks - Išgautas balansas bus pasiekiamas po %n blokoIšgautas balansas bus pasiekiamas po %n blokųIšgautas balansas bus pasiekiamas po %n blokų + + Mined balance will be available when it matures in %n more block(s) + - + This block was not received by any other nodes and will probably not be accepted! Šis blokas negautas nė vienu iš mazgų ir matomai nepriimtas - + Generated but not accepted Išgauta bet nepriimta - + Received with Gauta su - + Received from Gauta iš - + Sent to Siųsta - + Payment to yourself Mokėjimas sau - + Mined Išgauta - + (n/a) nepasiekiama - + Transaction status. Hover over this field to show number of confirmations. Sandorio būklė. Užvedus pelės žymeklį ant šios srities matysite patvirtinimų skaičių. - + Date and time that the transaction was received. Sandorio gavimo data ir laikas - + Type of transaction. - Sandorio tipas + Sandorio tipas. - + Destination address of transaction. Sandorio paskirties adresas - + Amount removed from or added to balance. Suma pridėta ar išskaičiuota iš balanso @@ -1693,818 +1964,961 @@ Adresas: %4 TransactionView - - + + All Visi - + Today Šiandien - + This week Šią savaitę - + This month Šį mėnesį - + Last month Paskutinį mėnesį - + This year Šiais metais - + Range... - Grupė + Intervalas... - + Received with Gauta su - + Sent to Išsiųsta - + To yourself Skirta sau - + Mined Išgauta - + Other Kita - + Enter address or label to search Įveskite adresą ar žymę į paiešką - + Min amount Minimali suma - + Copy address Kopijuoti adresą - + Copy label Kopijuoti žymę - + Copy amount Kopijuoti sumą - + + Copy transaction ID + + + + Edit label Taisyti žymę - + Show transaction details - + Rodyti sandėrio detales - + Export Transaction Data Sandorio duomenų eksportavimas - + Comma separated file (*.csv) Kableliais atskirtų duomenų failas (*.csv) - + Confirmed Patvirtintas - + Date Data - + Type Tipas - + Label Žymė - + Address Adresas - + Amount Suma - + ID ID - + Error exporting Eksportavimo klaida - + Could not write to file %1. Neįmanoma įrašyti į failą %1. - + Range: Grupė: - + to skirta - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopijuoti pasirinktą adresą į sistemos mainų atmintį - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Siunčiama + + Send Coins + Siųsti monetas - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &M sumažinti langą bet ne užduočių juostą - - - - Show only a tray icon after minimizing the window - Po programos lango sumažinimo rodyti tik programos ikoną. - - - - M&inimize on close + + Export the data in the current tab to a file - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Uždarant langą neuždaryti programos. Kai ši parinktis įjungta, programa bus uždaryta tik pasirinkus meniu komandą Baigti. + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - Bitcoin versija + + CasinoCoin version + CasinoCoin versija - + Usage: Naudojimas: - - Send command to -server or bitcoind - Siųsti komandą serveriui arba bitcoind + + Send command to -server or casinocoind + Siųsti komandą serveriui arba casinocoind - + List commands Komandų sąrašas - + Get help for a command Suteikti pagalba komandai - + Options: - Opcijos: + Parinktys: - - Specify configuration file (default: bitcoin.conf) - Nurodyti konfigūracijos failą (pagal nutylėjimąt: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Nurodyti konfigūracijos failą (pagal nutylėjimąt: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Nurodyti pid failą (pagal nutylėjimą: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Nurodyti pid failą (pagal nutylėjimą: casinocoind.pid) - - Generate coins - Sukurti monetas - - - - Don't generate coins - Neišgavinėti monetų - - - + Specify data directory - Nustatyti duomenų direktoriją + Nustatyti duomenų aplanką - + Set database cache size in megabytes (default: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Sujungimo klausymas prijungčiai <port> (pagal nutylėjimą: 47950 arba testnet: 17950) - - Specify connection timeout (in milliseconds) - Nustatyti sujungimo trukmę (milisekundėmis) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Sujungimo klausymas prijungčiai <port> (pagal nutylėjimą: 8333 arba testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Palaikyti ne daugiau <n> jungčių kolegoms (pagal nutylėjimą: 125) - - Connect only to the specified node - Prisijungti tik prie nurodyto mazgo - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Atjungimo dėl netinkamo kolegų elgesio riba (pagal nutylėjimą: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Sekundžių kiekis eikiamas palaikyti ryšį dėl lygiarangių nestabilumo (pagal nutylėjimą: 86.400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maksimalus buferis priėmimo sujungimui <n>*1000 bitų (pagal nutylėjimą: 10000) - - - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maksimalus buferis siuntimo sujungimui <n>*1000 bitų (pagal nutylėjimą: 10000) - - - - Detach block and address databases. Increases shutdown time (default: 0) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Klausymas JSON-RPC sujungimui prijungčiai <port> (pagal nutylėjimą: 47970 or testnet: 17970) + + + Accept command line and JSON-RPC commands Priimti komandinę eilutę ir JSON-RPC komandas - + Run in the background as a daemon and accept commands Dirbti fone kaip šešėlyje ir priimti komandas - + Use the test network Naudoti testavimo tinklą - - Output extra debugging information - Išėjimo papildomas derinimo informacija - - - - Prepend debug output with timestamp - Prideėti laiko žymę derinimo rezultatams - - - - Send trace/debug info to console instead of debug.log file - Siųsti atsekimo/derinimo info į konsolę vietoj debug.log failo - - - - Send trace/debug info to debugger - Siųsti sekimo/derinimo info derintojui - - - - Username for JSON-RPC connections - Vartotojo vardas JSON-RPC jungimuisi - - - - Password for JSON-RPC connections - Slaptažodis JSON-RPC sujungimams - - - - Listen for JSON-RPC connections on <port> (default: 8332) - Klausymas JSON-RPC sujungimui prijungčiai <port> (pagal nutylėjimą: 8332) - - - - Allow JSON-RPC connections from specified IP address - Leisti JSON-RPC tik iš nurodytų IP adresų - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Siųsti komandą mazgui dirbančiam <ip> (pagal nutylėjimą: 127.0.0.1) - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - Nustatyti rakto apimties dydį <n> (pagal nutylėjimą: 100) - - - - Rescan the block chain for missing wallet transactions - Ieškoti prarastų piniginės sandorių blokų grandinėje - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - SSL opcijos (žr.e Bitcoin Wiki for SSL setup instructions) - - - - Use OpenSSL (https) for JSON-RPC connections - Naudoti OpenSSL (https) jungimuisi JSON-RPC - - - - Server certificate file (default: server.cert) - Serverio sertifikato failas (pagal nutylėjimą: server.cert) - - - - Server private key (default: server.pem) - Serverio privatus raktas (pagal nutylėjimą: server.pem) - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Priimtini šifrai (pagal nutylėjimą: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - - - - - This help message - Pagelbos žinutė - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Negali gauti duomenų katalogo %s rakto. Bitcoin tikriausiai jau veikia. - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - Užkraunami adresai... - - - - Error loading blkindex.dat - blkindex.dat pakrovimo klaida - - - - Error loading wallet.dat: Wallet corrupted - wallet.dat pakrovimo klaida, wallet.dat sugadintas - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - wallet.dat pakrovimo klaida, wallet.dat reikalauja naujasnės Bitcoin versijos - - - - Wallet needed to be rewritten: restart Bitcoin to complete - Piniginė turi būti prrašyta: įvykdymui perkraukite Bitcoin - - - - Error loading wallet.dat - wallet.dat pakrovimo klaida - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - KLAIDA:nepavyko sudaryti sandorio - - - - Sending... - Siunčiama - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Klaida: sandoris buvo atmestas.Tai gali įvykti, jei kai kurios monetos iš jūsų piniginėje jau buvo panaudotos, pvz. jei naudojote wallet.dat kopiją ir monetos buvo išleistos kopijoje, bet nepažymėtos kaip skirtos išleisti čia. - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - Užkraunami blokų indeksai... - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - Užkraunama piniginė... - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - Peržiūra - - - - Done loading - Pakrovimas baigtas - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Įspėjimas: -paytxfee yra nustatytas per didelis. Tai sandorio mokestis, kurį turėsite mokėti, jei siųsite sandorį. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Įspėjimas: Patikrinkite, kad kompiuterio data ir laikas yra teisingi.Jei Jūsų laikrodis neteisingai nustatytas CasinoCoin, veiks netinkamai. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + Prisijungti tik prie nurodyto mazgo + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Neteisingas tor adresas: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maksimalus buferis priėmimo sujungimui <n>*1000 bitų (pagal nutylėjimą: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maksimalus buferis siuntimo sujungimui <n>*1000 bitų (pagal nutylėjimą: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + Išvesti papildomą derinimo informaciją. Numanomi visi kiti -debug* parametrai + + + + Output extra network debugging information + Išvesti papildomą tinklo derinimo informaciją + + + + Prepend debug output with timestamp + Prideėti laiko žymę derinimo rezultatams + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL opcijos (žr.e CasinoCoin Wiki for SSL setup instructions) + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + Siųsti atsekimo/derinimo info į konsolę vietoj debug.log failo + + + + Send trace/debug info to debugger + Siųsti sekimo/derinimo info derintojui + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Nustatyti sujungimo trukmę milisekundėmis (pagal nutylėjimą: 5000) + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Bandymas naudoti UPnP struktūra klausymosi prievadui (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Bandymas naudoti UPnP struktūra klausymosi prievadui (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + Vartotojo vardas JSON-RPC jungimuisi + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Slaptažodis JSON-RPC sujungimams + + + + Allow JSON-RPC connections from specified IP address + Leisti JSON-RPC tik iš nurodytų IP adresų + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Siųsti komandą mazgui dirbančiam <ip> (pagal nutylėjimą: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + Atnaujinti piniginę į naujausią formatą + + + + Set key pool size to <n> (default: 100) + Nustatyti rakto apimties dydį <n> (pagal nutylėjimą: 100) + + + + Rescan the block chain for missing wallet transactions + Ieškoti prarastų piniginės sandorių blokų grandinėje + + + + Use OpenSSL (https) for JSON-RPC connections + Naudoti OpenSSL (https) jungimuisi JSON-RPC + + + + Server certificate file (default: server.cert) + Serverio sertifikato failas (pagal nutylėjimą: server.cert) + + + + Server private key (default: server.pem) + Serverio privatus raktas (pagal nutylėjimą: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Priimtini šifrai (pagal nutylėjimą: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Pagelbos žinutė + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Nepavyko susieti šiame kompiuteryje prievado %s (bind returned error %d, %s) + + + + Connect through socks proxy + Jungtis per socks tarpinį serverį + + + + Allow DNS lookups for -addnode, -seednode and -connect + Leisti DNS paiešką sujungimui ir mazgo pridėjimui + + + + Loading addresses... + Užkraunami adresai... + + + + Error loading wallet.dat: Wallet corrupted + wallet.dat pakrovimo klaida, wallet.dat sugadintas + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + wallet.dat pakrovimo klaida, wallet.dat reikalauja naujasnės CasinoCoin versijos + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Piniginė turi būti prrašyta: įvykdymui perkraukite CasinoCoin + + + + Error loading wallet.dat + wallet.dat pakrovimo klaida + + + + Invalid -proxy address: '%s' + Neteisingas proxy adresas: '%s' + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + Neteisinga suma -paytxfee=<amount>: '%s' + + + + Invalid amount + Neteisinga suma + + + + Insufficient funds + Nepakanka lėšų + + + + Loading block index... + Įkeliamas blokų indeksas... + + + + Add a node to connect to and attempt to keep the connection open + Pridėti mazgą prie sujungti su and attempt to keep the connection open + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Nepavyko susieti šiame kompiuteryje prievado %s. CasinoCoin tikriausiai jau veikia. + + + + Fee per KB to add to transactions you send + Įtraukti mokestį už kB siunčiamiems sandoriams + + + + Loading wallet... + Užkraunama piniginė... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + Peržiūra + + + + Done loading + Įkėlimas baigtas + + + + To use the %s option + + + + Error - + Klaida - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Įspėjimas: Patikrinkite, kad kompiuterio data ir laikas yra teisingi.Jei Jūsų laikrodis neteisingai nustatytas Bitcoin, veiks netinkamai. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts new file mode 100644 index 0000000..1e06e2a --- /dev/null +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -0,0 +1,2923 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + Par CasinoCoin + + + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versija + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + Adrešu grāmata + + + + Double-click to edit address or label + Adresi vai nosaukumu rediģē ar dubultklikšķi + + + + Create a new address + Izveidot jaunu adresi + + + + Copy the currently selected address to the system clipboard + Kopēt iezīmēto adresi uz starpliktuvi + + + + &New Address + &Jauna adrese + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + &Kopēt adresi + + + + Show &QR Code + Parādīt &QR kodu + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + &Dzēst + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + Kopēt &Nosaukumu + + + + &Edit + &Rediģēt + + + + Send &Coins + + + + + Export Address Book Data + Eksportēt adreses + + + + Comma separated file (*.csv) + Fails ar komatu kā atdalītāju (*.csv) + + + + Error exporting + Kļūda eksportējot + + + + Could not write to file %1. + Nevar ierakstīt failā %1. + + + + AddressTableModel + + + Label + Nosaukums + + + + Address + Adrese + + + + (no label) + (bez nosaukuma) + + + + AskPassphraseDialog + + + Passphrase Dialog + Paroles dialogs + + + + Enter passphrase + Ierakstiet paroli + + + + New passphrase + Jauna parole + + + + Repeat new passphrase + Jaunā parole vēlreiz + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Ierakstiet maciņa jauno paroli.<br/>Lūdzu izmantojiet <b>10 vai vairāk nejauši izvēlētas zīmes</b>, vai <b>astoņus un vairāk vārdus</b>. + + + + Encrypt wallet + Šifrēt maciņu + + + + This operation needs your wallet passphrase to unlock the wallet. + Lai veikto šo darbību, maciņš jāatslēdz ar paroli. + + + + Unlock wallet + Atslēgt maciņu + + + + This operation needs your wallet passphrase to decrypt the wallet. + Šai darbībai maciņš jāatšifrē ar maciņa paroli. + + + + Decrypt wallet + Atšifrēt maciņu + + + + Change passphrase + Mainīt paroli + + + + Enter the old and new passphrase to the wallet. + Ierakstiet maciņa veco un jauno paroli. + + + + Confirm wallet encryption + Apstiprināt maciņa šifrēšanu + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + Maciņš nošifrēts + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin aizvērsies, lai pabeigtu šifrēšanu. Atcerieties, ka maciņa šifrēšana nevar pilnībā novērst bitkoinu zādzību, ko veic datorā ieviesušās kaitīgas programmas. + + + + + + + Wallet encryption failed + Maciņa šifrēšana neizdevās + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Maciņa šifrēšana neizdevās programmas kļūdas dēļ. Jūsu maciņš netika šifrēts. + + + + + The supplied passphrases do not match. + Ievadītās paroles nav vienādas. + + + + Wallet unlock failed + Maciņu atšifrēt neizdevās + + + + + + The passphrase entered for the wallet decryption was incorrect. + Maciņa atšifrēšanai ievadītā parole nav pareiza. + + + + Wallet decryption failed + Maciņu neizdevās atšifrēt + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + Parakstīt &ziņojumu... + + + + Synchronizing with network... + Sinhronizācija ar tīklu... + + + + &Overview + &Pārskats + + + + Show general overview of wallet + Rādīt vispārēju maciņa pārskatu + + + + &Transactions + &Transakcijas + + + + Browse transaction history + Skatīt transakciju vēsturi + + + + Edit the list of stored addresses and labels + Rediģēt saglabātās adreses un nosaukumus + + + + Show the list of addresses for receiving payments + Rādīt maksājumu saņemšanas adreses + + + + E&xit + &Iziet + + + + Quit application + Aizvērt programmu + + + + Show information about CasinoCoin + Parādīt informāciju par CasinoCoin + + + + About &Qt + Par &Qt + + + + Show information about Qt + Parādīt informāciju par Qt + + + + &Options... + &Iespējas + + + + &Encrypt Wallet... + Š&ifrēt maciņu... + + + + &Backup Wallet... + &Izveidot maciņa rezerves kopiju + + + + &Change Passphrase... + &Mainīt paroli + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + Nosūtīt bitkoinus uz CasinoCoin adresi + + + + Modify configuration options for CasinoCoin + Mainīt CasinoCoin konfigurācijas uzstādījumus + + + + Backup wallet to another location + Izveidot maciņa rezerves kopiju citur + + + + Change the passphrase used for wallet encryption + Mainīt maciņa šifrēšanas paroli + + + + &Debug window + &Debug logs + + + + Open debugging and diagnostic console + Atvērt atkļūdošanas un diagnostikas konsoli + + + + &Verify message... + &Pārbaudīt ziņojumu... + + + + + CasinoCoin + + + + + Wallet + Maciņš + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + &Fails + + + + &Settings + &Uzstādījumi + + + + &Help + &Palīdzība + + + + Tabs toolbar + Ciļņu rīkjosla + + + + + [testnet] + [testnet] + + + + CasinoCoin client + CasinoCoin klients + + + + %n active connection(s) to CasinoCoin network + %n aktīvu savienojumu ar CasinoCoin tīklu%n aktīvs savienojums ar CasinoCoin tīklu%n aktīvu savienojumu as CasinoCoin tīklu + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + Kļūda + + + + Warning + Brīdinājums + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + Sinhronizēts + + + + Catching up... + Sinhronizējos... + + + + Confirm transaction fee + Apstiprināt transakcijas maksu + + + + Sent transaction + Transakcija nosūtīta + + + + Incoming transaction + Ienākoša transakcija + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + Datums: %1 +Daudzums: %2 +Tips: %3 +Adrese: %4 + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Maciņš ir <b>šifrēts</b> un pašlaik <b>atslēgts</b> + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Maciņš ir <b>šifrēts</b> un pašlaik <b>slēgts</b> + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + Tīkla brīdinājums + + + + EditAddressDialog + + + Edit Address + Mainīt adrese + + + + &Label + &Nosaukums + + + + The label associated with this address book entry + Adrešu grāmatas ieraksta nosaukums + + + + &Address + &Adrese + + + + The address associated with this address book entry. This can only be modified for sending addresses. + Adrese adrešu grāmatas ierakstā. To var mainīt tikai nosūtīšanas adresēm. + + + + New receiving address + Jauna saņemšanas adrese + + + + New sending address + Jauna nosūtīšanas adrese + + + + Edit receiving address + Mainīt saņemšanas adresi + + + + Edit sending address + Mainīt nosūtīšanas adresi + + + + The entered address "%1" is already in the address book. + Nupat ierakstītā adrese "%1" jau atrodas adrešu grāmatā. + + + + The entered address "%1" is not a valid CasinoCoin address. + Ierakstītā adrese "%1" nav derīga CasinoCoin adrese. + + + + Could not unlock wallet. + Nav iespējams atslēgt maciņu. + + + + New key generation failed. + Neizdevās ģenerēt jaunu atslēgu. + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + CasinoCoin-Qt + + + + version + versija + + + + Usage: + Lietojums: + + + + command-line options + komandrindas izvēles + + + + UI options + Lietotāja interfeisa izvēlnes + + + + Set language, for example "de_DE" (default: system locale) + Uzstādiet valodu, piemēram "de_DE" (pēc noklusēšanas: sistēmas lokāle) + + + + Start minimized + Sākt minimizētu + + + + Show splash screen on startup (default: 1) + Uzsākot, parādīt programmas informācijas logu (pēc noklusēšanas: 1) + + + + OptionsDialog + + + Options + Iespējas + + + + &Main + &Galvenais + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + &Maksāt par transakciju + + + + Automatically start CasinoCoin after logging in to the system. + Automātiski sākt CasinoCoin pēc pieteikšanās sistēmā. + + + + &Start CasinoCoin on system login + &Sākt CasinoCoin reizē ar sistēmu + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + &Tīkls + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Uz rūtera automātiski atvērt CasinoCoin klienta portu. Tas strādā tikai tad, ja rūteris atbalsta UPnP un tas ir ieslēgts. + + + + Map port using &UPnP + Kartēt portu, izmantojot &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + &Savienoties caur SOCKS proxy: + + + + Proxy &IP: + Proxy &IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + proxy IP adrese (piem. 127.0.0.1) + + + + &Port: + &Ports: + + + + Port of the proxy (e.g. 9050) + Proxy ports (piem. 9050) + + + + SOCKS &Version: + SOCKS &Versija: + + + + SOCKS version of the proxy (e.g. 5) + proxy SOCKS versija (piem. 5) + + + + &Window + &Logs + + + + Show only a tray icon after minimizing the window. + Pēc loga minimizācijas rādīt tikai ikonu sistēmas teknē. + + + + &Minimize to the tray instead of the taskbar + &Minimizēt uz sistēmas tekni, nevis rīkjoslu + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Logu aizverot, minimizēt, nevis beigt darbu. Kad šī izvēlne iespējota, programma aizvērsies tikai pēc Beigt komandas izvēlnē. + + + + M&inimize on close + M&inimizēt aizverot + + + + &Display + &Izskats + + + + User Interface &language: + Lietotāja interfeiss un &valoda: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Šeit var iestatīt lietotāja valodu. Iestatījums aktivizēsies pēc CasinoCoin pārstartēšanas. + + + + &Unit to show amounts in: + &Vienības, kurās attēlot daudzumus: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Izvēlēties dalījuma vienību pēc noklusēšanas, ko izmantot interfeisā un nosūtot bitkoinus. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Rādīt vai nē CasinoCoin adreses transakciju sarakstā. + + + + &Display addresses in transaction list + &Attēlot adreses transakciju sarakstā + + + + &OK + &OK + + + + &Cancel + &Atcelt + + + + &Apply + &Pielietot + + + + default + pēc noklusēšanas + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Brīdinājums + + + + + This setting will take effect after restarting CasinoCoin. + Iestatījums aktivizēsies pēc Bitkoin pārstartēšanas. + + + + The supplied proxy address is invalid. + Norādītā proxy adrese nav derīga. + + + + OverviewPage + + + Form + Forma + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Attēlotā informācija var būt novecojusi. Jūsu maciņš pēc savienojuma izveides automātiski sinhronizējas ar CasinoCoin tīklu, taču šis process vēl nav beidzies. + + + + Balance: + Bilance: + + + + Unconfirmed: + Neapstiprinātas: + + + + Wallet + Maciņš + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + <b>Pēdējās transakcijas</b> + + + + Your current balance + Jūsu tekošā bilance + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + Kopējā apstiprināmo transakciju vērtība, vēl nav ieskaitīta kopējā bilancē + + + + + out of sync + nav sinhronizēts + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + QR koda dialogs + + + + Request Payment + Pieprasīt maksājumu + + + + Amount: + Daudzums: + + + + Label: + Nosaukums: + + + + Message: + Ziņojums: + + + + &Save As... + &Saglabāt kā... + + + + Error encoding URI into QR Code. + Kļūda kodējot URI QR kodā. + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + Rezultāta URI pārāk garš, mēģiniet saīsināt nosaukumu vai ziņojumu. + + + + Save QR Code + Saglabāt QR kodu + + + + PNG Images (*.png) + PNG attēli (*.png) + + + + RPCConsole + + + Client name + Klienta vārds + + + + + + + + + + + + + N/A + N/A + + + + Client version + Klienta versija + + + + &Information + &Informācija + + + + Using OpenSSL version + + + + + Startup time + Sākuma laiks + + + + Network + Tīkls + + + + Number of connections + Savienojumu skaits + + + + On testnet + Testa tīklā + + + + Block chain + Bloku virkne + + + + Current number of blocks + Pašreizējais bloku skaits + + + + Estimated total blocks + Bloku skaita novērtējums + + + + Last block time + Pēdējā bloka laiks + + + + &Open + &Atvērt + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + &Konsole + + + + Build date + Kompilācijas datums + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + Notīrīt konsoli + + + + Welcome to the CasinoCoin RPC console. + Laipni lūgti CasinoCoin RPC konsolē. + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Izmantojiet bultiņas uz augšu un leju, lai pārvietotos pa vēsturi, un <b>Ctrl-L</b> ekrāna notīrīšanai. + + + + Type <b>help</b> for an overview of available commands. + Ierakstiet <b>help</b> lai iegūtu pieejamo komandu sarakstu. + + + + SendCoinsDialog + + + + + + + + + + Send Coins + Sūtīt bitkoinus + + + + Send to multiple recipients at once + Sūtīt vairākiem saņēmējiem uzreiz + + + + Add &Recipient + + + + + Remove all transaction fields + Dzēst visus transakcijas laukus + + + + Clear &All + &Notīrīt visu + + + + Balance: + Bilance: + + + + 123.456 BTC + 123,456 BTC + + + + Confirm the send action + Apstiprināt nosūtīšanu + + + + S&end + + + + + <b>%1</b> to %2 (%3) + <b>%1</b> līdz %2 (%3) + + + + Confirm send coins + Apstiprināt bitkoinu sūtīšanu + + + + Are you sure you want to send %1? + Vai tiešām vēlaties nosūtīt %1? + + + + and + un + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + Nosūtāmajai summai jābūt lielākai par 0. + + + + The amount exceeds your balance. + Daudzums pārsniedz pieejamo. + + + + The total exceeds your balance when the %1 transaction fee is included. + Kopsumma pārsniedz pieejamo, ja pieskaitīta %1 transakcijas maksa. + + + + Duplicate address found, can only send to each address once per send operation. + Atrastas divas vienādas adreses, vienā nosūtīšanas reizē uz katru adresi var sūtīt tikai vienreiz. + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Kļūda: transakcija tika atteikta. Tā var gadīties, ja kāds no maciņā esošiem bitkoiniem jau iztērēts, piemēram, izmantojot wallet.dat kopiju, kurā nav atzīmēti iztērētie bitkoini. + + + + SendCoinsEntry + + + Form + Forma + + + + A&mount: + Apjo&ms + + + + Pay &To: + &Saņēmējs: + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + Lai pievienotu adresi adrešu grāmatai, tai jādod nosaukums + + + + &Label: + &Nosaukums: + + + + Choose address from address book + Izvēlēties adresi no adrešu grāmatas + + + + Alt+A + Alt+A + + + + Paste address from clipboard + ielīmēt adresi no starpliktuves + + + + Alt+P + Alt+P + + + + Remove this recipient + Dzēst šo saņēmēju + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Ierakstiet CasinoCoin adresi (piem. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + ielīmēt adresi no starpliktuves + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + &Notīrīt visu + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Ierakstiet CasinoCoin adresi (piem. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + Atvērts līdz %1 + + + + %1/offline + + + + + %1/unconfirmed + %1/neapstiprinātas + + + + %1 confirmations + %1 apstiprinājumu + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + Datums + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + Daudzums + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + , vēl nav veiksmīgi izziņots + + + + Open for %n more block(s) + + + + + unknown + nav zināms + + + + TransactionDescDialog + + + Transaction details + Transakcijas detaļas + + + + This pane shows a detailed description of the transaction + Šis panelis parāda transakcijas detaļas + + + + TransactionTableModel + + + Date + Datums + + + + Type + Tips + + + + Address + Adrese + + + + Amount + Daudzums + + + + Open for %n more block(s) + + + + + Open until %1 + Atvērts līdz %1 + + + + Offline (%1 confirmations) + Nav pieslēgts (%1 apstiprinājumu) + + + + Unconfirmed (%1 of %2 confirmations) + Nav apstiprināts (%1 no %2 apstiprinājumu) + + + + Confirmed (%1 confirmations) + Apstiprināts (%1 apstiprinājumu) + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + Neviens cits mezgls šo bloku nav saņēmis un droši vien netiks akceptēts! + + + + Generated but not accepted + Ģenerēts, taču nav akceptēts + + + + Received with + Saņemts ar + + + + Received from + Saņemts no + + + + Sent to + Nosūtīts + + + + Payment to yourself + Maksājums sev + + + + Mined + Atrasts + + + + (n/a) + (nav pieejams) + + + + Transaction status. Hover over this field to show number of confirmations. + Transakcijas statuss. Turiet peli virs šī lauka, lai redzētu apstiprinājumu skaitu. + + + + Date and time that the transaction was received. + Transakcijas saņemšanas datums un laiks. + + + + Type of transaction. + Transakcijas tips. + + + + Destination address of transaction. + Transakcijas mērķa adrese. + + + + Amount removed from or added to balance. + Bilancei pievienotais vai atņemtais daudzums. + + + + TransactionView + + + + All + Visi + + + + Today + Šodien + + + + This week + Šonedēļ + + + + This month + Šomēnes + + + + Last month + Pēdējais mēnesis + + + + This year + Šogad + + + + Range... + Diapazons... + + + + Received with + Saņemts ar + + + + Sent to + Nosūtīts + + + + To yourself + Sev + + + + Mined + Atrasts + + + + Other + Cits + + + + Enter address or label to search + Ierakstiet meklējamo nosaukumu vai adresi + + + + Min amount + Minimālais daudzums + + + + Copy address + Kopēt adresi + + + + Copy label + Kopēt nosaukumu + + + + Copy amount + Kopēt daudzumu + + + + Copy transaction ID + + + + + Edit label + Mainīt nosaukumu + + + + Show transaction details + Rādīt transakcijas detaļas + + + + Export Transaction Data + Eksportēt transakcijas datus + + + + Comma separated file (*.csv) + Fails ar komatu kā atdalītāju (*.csv) + + + + Confirmed + Apstiprināts + + + + Date + Datums + + + + Type + Tips + + + + Label + Nosaukums + + + + Address + Adrese + + + + Amount + Daudzums + + + + ID + ID + + + + Error exporting + Eksportēšanas kļūda + + + + Could not write to file %1. + Nevar ierakstīt failā %1. + + + + Range: + Diapazons: + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + Izveidot maciņa rezerves kopiju + + + + Wallet Data (*.dat) + Maciņa dati (*.dat) + + + + Backup Failed + Rezerves kopēšana neizdevās + + + + There was an error trying to save the wallet data to the new location. + Kļūda, saglabājot maciņu jaunajā vietā. + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + CasinoCoin versija + + + + Usage: + Lietojums: + + + + Send command to -server or casinocoind + Nosūtīt komantu uz -server vai casinocoind + + + + List commands + Komandu saraksts + + + + Get help for a command + Palīdzība par komandu + + + + Options: + Iespējas: + + + + Specify configuration file (default: casinocoin.conf) + Norādiet konfigurācijas failu (pēc noklusēšanas: casinocoin.conf) + + + + Specify pid file (default: casinocoind.pid) + Norādiet pid failu (pēc noklusēšanas: casinocoind.pid) + + + + Specify data directory + Norādiet datu direktoriju + + + + Set database cache size in megabytes (default: 25) + Uzstādiet datu bāzes bufera izmēru megabaitos (pēc noklusēšanas: 25) + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Gaidīt savienojumus portā <port> (pēc noklusēšanas: 47950 vai testnet: 17950) + + + + Maintain at most <n> connections to peers (default: 125) + Uzturēt līdz <n> savienojumiem ar citiem mezgliem(pēc noklusēšanas: 125) + + + + Connect to a node to retrieve peer addresses, and disconnect + Pievienoties mezglam, lai iegūtu citu mezglu adreses, un atvienoties + + + + Specify your own public address + Norādiet savu publisko adresi + + + + Threshold for disconnecting misbehaving peers (default: 100) + Slieksnis pārkāpējmezglu atvienošanai (pēc noklusēšanas: 100) + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Sekundes, cik ilgi atturēt pārkāpējmezglus no atkārtotas pievienošanās (pēc noklusēšanas: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + Pieņemt komandrindas un JSON-RPC komandas + + + + Run in the background as a daemon and accept commands + Darbināt fonā kā servisu un pieņemt komandas + + + + Use the test network + Izmantot testa tīklu + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + Debug izvadei sākumā pievienot laika zīmogu + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + Debug/trace informāciju izvadīt konsolē, nevis debug.log failā + + + + Send trace/debug info to debugger + Debug/trace informāciju izvadīt debug programmai + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + JSON-RPC savienojumu lietotājvārds + + + + Warning + Brīdinājums + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + JSON-RPC savienojumu parole + + + + Allow JSON-RPC connections from specified IP address + Atļaut JSON-RPC savienojumus no norādītās IP adreses + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Nosūtīt komandas mezglam, kas darbojas adresē <ip> (pēc noklusēšanas: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Izpildīt komandu, kad labāk atbilstošais bloks izmainās (%s cmd aizvieto ar bloka hešu) + + + + Upgrade wallet to latest format + Atjaunot maciņa formātu uz jaunāko + + + + Set key pool size to <n> (default: 100) + Uzstādīt atslēgu bufera izmēru uz <n> (pēc noklusēšanas: 100) + + + + Rescan the block chain for missing wallet transactions + Atkārtoti skanēt bloku virkni, meklējot trūkstošās maciņa transakcijas + + + + Use OpenSSL (https) for JSON-RPC connections + JSON-RPC savienojumiem izmantot OpenSSL (https) + + + + Server certificate file (default: server.cert) + Servera sertifikāta fails (pēc noklusēšanas: server.cert) + + + + Server private key (default: server.pem) + Servera privātā atslēga (pēc noklusēšanas: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Pieņemamie šifri (pēc noklusēšanas: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Šis palīdzības paziņojums + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Nevar pievienoties pie %s šajā datorā (pievienošanās atgrieza kļūdu %d, %s) + + + + Connect through socks proxy + Savienoties caurs socks proxy + + + + Allow DNS lookups for -addnode, -seednode and -connect + Atļaut DNS uzmeklēšanu priekš -addnode, -seednode un -connect + + + + Loading addresses... + Ielādē adreses... + + + + Error loading wallet.dat: Wallet corrupted + Nevar ielādēt wallet.dat: maciņš bojāts + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Nevar ielādēt wallet.dat: maciņa atvēršanai nepieciešama jaunāka CasinoCoin versija + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Bija nepieciešams pārstartēt maciņu: pabeigšanai pārstartējiet CasinoCoin + + + + Error loading wallet.dat + Kļūda ielādējot wallet.dat + + + + Invalid -proxy address: '%s' + Nederīga -proxy adrese: '%s' + + + + Unknown network specified in -onlynet: '%s' + -onlynet komandā norādīts nepazīstams tīkls: '%s' + + + + Unknown -socks proxy version requested: %i + Pieprasīta nezināma -socks proxy versija: %i + + + + Cannot resolve -bind address: '%s' + Nevar uzmeklēt -bind adresi: '%s' + + + + Cannot resolve -externalip address: '%s' + Nevar atrisināt -externalip adresi: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Nederīgs daudzums priekš -paytxfree=<amount>: '%s' + + + + Invalid amount + Nederīgs daudzums + + + + Insufficient funds + Nepietiek bitkoinu + + + + Loading block index... + Ielādē bloku indeksu... + + + + Add a node to connect to and attempt to keep the connection open + Pievienot mezglu, kam pievienoties un turēt savienojumu atvērtu + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Nevar pievienoties %s uz šī datora. CasinoCoin droši vien jau darbojas. + + + + Fee per KB to add to transactions you send + Maksa par KB, ko pievienot nosūtāmajām transakcijām + + + + Loading wallet... + Ielādē maciņu... + + + + Cannot downgrade wallet + Nevar maciņa formātu padarīt vecāku + + + + Cannot write default address + Nevar ierakstīt adresi pēc noklusēšanas + + + + Rescanning... + Skanēju no jauna... + + + + Done loading + Ielāde pabeigta + + + + To use the %s option + Izmantot opciju %s + + + + Error + Kļūda + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + Konfigurācijas failā jāuzstāda rpcpassword=<password>: +%s +Ja fails neeksistē, izveidojiet to ar atļauju lasīšanai tikai īpašniekam. + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 8f32f6b..d4a97f6 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - Om Bitcoin + + About CasinoCoin + Om CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versjon + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versjon - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Utviklerne - + Dette er eksperimentell programvare. -Distribuert under MIT/X11 programvarelisensen, se medfølgende fil license.txt eller http://www.opensource.org/licenses/mit-license.php. +Distribuert under MIT/X11 programvarelisensen, se medfølgende fil COPYING eller http://www.opensource.org/licenses/mit-license.php. Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i OpenSSL Toolkit (http://www.openssl.org/) og kryptografisk programvare skrevet av Eric Young (eay@cryptsoft.com) og UPnP programvare skrevet av Thomas Bernard. + + + Copyright + + + + + The CasinoCoin developers + + AddressBookPage - + Address Book Adressebok - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Dette er dine Bitcoin adresser for å motta betalinger. Du kan gi en separat adresse til hver avsender slik at du kan holde oversikt over hvem som betaler deg. - - - + Double-click to edit address or label Dobbeltklikk for å redigere adresse eller merkelapp - + Create a new address Lag en ny adresse - + Copy the currently selected address to the system clipboard Kopier den valgte adressen til systemets utklippstavle - + &New Address - + &Ny Adresse - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Dette er dine CasinoCoin-adresser for mottak av betalinger. Du kan gi forskjellige adresser til alle som skal betale deg for å holde bedre oversikt. + + + &Copy Address - + &Kopier Adresse - + Show &QR Code Vis &QR Kode - - Sign a message to prove you own this address - Signér en melding for å bevise at du eier denne adressen + + Sign a message to prove you own a CasinoCoin address + Signer en melding for å bevise at du eier en CasinoCoin-adresse - - &Sign Message - &Signér Melding + + Sign &Message + Signér &Melding - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Slett den valgte adressen fra listen. Bare adresser for sending kan slettes. + + Delete the currently selected address from the list + Slett den valgte adressen fra listen. - + + Export the data in the current tab to a file + Eksporter data fra nåværende fane til fil + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verifiser en melding for å være sikker på at den ble signert av en angitt CasinoCoin-adresse + + + + &Verify Message + &Verifiser Melding + + + &Delete &Slett - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Kopier &Merkelapp - + &Edit - + &Rediger - + + Send &Coins + Send &Coins + + + Export Address Book Data Eksporter adressebok - + Comma separated file (*.csv) Kommaseparert fil (*.csv) - + Error exporting Feil ved eksportering - + Could not write to file %1. Kunne ikke skrive til filen %1. @@ -126,17 +164,17 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i AddressTableModel - + Label Merkelapp - + Address Adresse - + (no label) (ingen merkelapp) @@ -144,432 +182,460 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i AskPassphraseDialog - + Passphrase Dialog - + Dialog for Adgangsfrase - + Enter passphrase Angi adgangsfrase - + New passphrase Ny adgangsfrase - + Repeat new passphrase Gjenta ny adgangsfrase - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Skriv inn den nye adgangsfrasen for lommeboken.<br/>Vennligst bruk en adgangsfrase med <b>10 eller flere tilfeldige tegn</b>, eller <b>åtte eller flere ord</b>. - + Encrypt wallet Krypter lommebok - + This operation needs your wallet passphrase to unlock the wallet. Denne operasjonen krever adgangsfrasen til lommeboken for å låse den opp. - + Unlock wallet Lås opp lommebok - + This operation needs your wallet passphrase to decrypt the wallet. Denne operasjonen krever adgangsfrasen til lommeboken for å dekryptere den. - + Decrypt wallet Dekrypter lommebok - + Change passphrase Endre adgangsfrase - + Enter the old and new passphrase to the wallet. Skriv inn gammel og ny adgangsfrase for lommeboken. - + Confirm wallet encryption Bekreft kryptering av lommebok - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ADVARSEL: Hvis du krypterer lommeboken og mister adgangsfrasen vil du <b>MISTE ALLE DINE BITCOINS</b>! -Er du sikker på at du vil kryptere lommeboken? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Advarsel: Hvis du krypterer lommeboken og mister adgangsfrasen, så vil du <b>MISTE ALLE DINE CASINOCOINS</b>! - - + + Are you sure you wish to encrypt your wallet? + Er du sikker på at du vil kryptere lommeboken? + + + + 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. + VIKTIG: Tidligere sikkerhetskopier av din lommebok-fil, bør erstattes med den nylig genererte, krypterte filen, da de blir ugyldiggjort av sikkerhetshensyn så snart du begynner å bruke den nye krypterte lommeboken. + + + + + Warning: The Caps Lock key is on! + Advarsel: Caps Lock er på ! + + + + Wallet encrypted Lommebok kryptert - - Bitcoin 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. - Bitcoin vil nå lukkes for å fullføre krypteringsprosessen. Husk at kryptering av lommeboken ikke fullt ut kan beskytte dine bitcoins fra å bli stjålet om skadevare infiserer datamaskinen. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin vil nå lukkes for å fullføre krypteringsprosessen. Husk at kryptering av lommeboken ikke fullt ut kan beskytte dine casinocoins fra å bli stjålet om skadevare infiserer datamaskinen. - - - Warning: The Caps Lock key is on. - Advarsel: Caps lock tasten er på. - - - - - - + + + + Wallet encryption failed Kryptering av lommebok feilet - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Kryptering av lommebok feilet på grunn av en intern feil. Din lommebok ble ikke kryptert. - - + + The supplied passphrases do not match. De angitte adgangsfrasene er ulike. - + Wallet unlock failed Opplåsing av lommebok feilet - - - + + + The passphrase entered for the wallet decryption was incorrect. Adgangsfrasen angitt for dekryptering av lommeboken var feil. - + Wallet decryption failed Dekryptering av lommebok feilet - - Wallet passphrase was succesfully changed. - Lommebokens adgangsfrase ble endret. + + Wallet passphrase was successfully changed. + Adgangsfrase for lommebok endret. BitcoinGUI - - Bitcoin Wallet - Bitcoin Lommebok - - - + Sign &message... - + Signer &melding... - - Show/Hide &Bitcoin - Gjem/vis &Bitcoin - - - + Synchronizing with network... Synkroniserer med nettverk... - + &Overview &Oversikt - + Show general overview of wallet Vis generell oversikt over lommeboken - + &Transactions &Transaksjoner - + Browse transaction history Vis transaksjonshistorikk - - &Address Book - &Adressebok - - - + Edit the list of stored addresses and labels Rediger listen over adresser og deres merkelapper - - &Receive coins - &Motta bitcoins - - - + Show the list of addresses for receiving payments Vis listen over adresser for mottak av betalinger - - &Send coins - &Send bitcoins - - - - Prove you control an address - Bevis at du kontrollerer en adresse - - - + E&xit &Avslutt - + Quit application Avslutt applikasjonen - - &About %1 - &Om %1 + + Show information about CasinoCoin + Vis informasjon om CasinoCoin - - Show information about Bitcoin - Vis informasjon om Bitcoin - - - + About &Qt Om &Qt - + Show information about Qt Vis informasjon om Qt - + &Options... &Innstillinger... - + &Encrypt Wallet... - + &Krypter Lommebok... - + &Backup Wallet... - + Lag &Sikkerhetskopi av Lommebok... - + &Change Passphrase... - - - - - ~%n block(s) remaining - ~%n blokk gjenstår~%n blokker gjenstår + &Endre Adgangsfrase... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Lastet ned %1 av %2 blokker med transaksjonshistorikk (%3% ferdig). + + Importing blocks from disk... + Importere blokker... - - &Export... - &Eksporter... + + Reindexing blocks on disk... + Re-indekserer blokker på disk... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Send til en CasinoCoin-adresse - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Endre oppsett for CasinoCoin - - Show or hide the Bitcoin window - Vis eller gjem Bitcoinvinduet - - - - Export the data in the current tab to a file - Eksporter data fra nåværende fane til fil - - - - Encrypt or decrypt wallet - Krypter eller dekrypter lommebok - - - + Backup wallet to another location Sikkerhetskopiér lommebok til annet sted - + Change the passphrase used for wallet encryption Endre adgangsfrasen brukt for kryptering av lommebok - + &Debug window - + &Feilsøkingsvindu - + Open debugging and diagnostic console - + Åpne konsoll for feilsøk og diagnostikk - + &Verify message... - + &Verifiser melding... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Lommebok + + + + &Send + &Send + + + + &Receive + &Motta + + + + &Addresses + &Adressebok + + + + &About CasinoCoin + &Om CasinoCoin + + + + &Show / Hide + &Gjem / vis + + + + Show or hide the main Window + Vis eller skjul hovedvinduet + + + + Encrypt the private keys that belong to your wallet + Krypter de private nøklene som tilhører lommeboken din + + + + Sign messages with your CasinoCoin addresses to prove you own them + Signér en melding for å bevise at du eier denne adressen + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Bekreft meldinger for å være sikker på at de ble signert av en angitt CasinoCoin-adresse + + + &File &Fil - + &Settings &Innstillinger - + &Help &Hjelp - + Tabs toolbar Verktøylinje for faner - - Actions toolbar - Verktøylinje for handlinger - - - - + + [testnet] [testnett] - - - Bitcoin client - Bitcoinklient + + CasinoCoin client + CasinoCoinklient - - %n active connection(s) to Bitcoin network - %n aktiv forbindelse til Bitcoin-nettverket%n aktive forbindelser til Bitcoin-nettverket + + %n active connection(s) to CasinoCoin network + %n aktiv forbindelse til CasinoCoin-nettverket%n aktive forbindelser til CasinoCoin-nettverket - - Downloaded %1 blocks of transaction history. - Lastet ned %1 blokker med transaksjonshistorikk. - - - - %n second(s) ago - for %n sekund sidenfor %n sekunder siden - - - - %n minute(s) ago - for %n minutt sidenfor %n minutter siden - - - - %n hour(s) ago - for %n time sidenfor %n timer siden - - - - %n day(s) ago - for %n dag sidenfor %n dager siden + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + Lastet %1 blokker med transaksjonshistorikk. + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + Transaksjoner etter dette vil ikke være synlige enda. + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Denne transaksjonen overstiger størrelsesbegrensningen. Du kan likevel sende den med et gebyr på %1, som går til nodene som prosesserer transaksjonen din og støtter nettverket. Vil du betale gebyret? + + + Up to date Ajour - + Catching up... Kommer ajour... - - Last received block was generated %1. - Siste mottatte blokk ble generert %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Denne transaksjonen overstiger størrelsesbegrensningen. Du kan likevel sende den med et gebyr på %1, som går til nodene som prosesserer transaksjonen din og støtter nettverket. Vil du betale gebyret? - - - + Confirm transaction fee - + Bekreft transaksjonsgebyr - + Sent transaction Sendt transaksjon - + Incoming transaction Innkommende transaksjon - + Date: %1 Amount: %2 Type: %3 @@ -582,539 +648,486 @@ Adresse: %4 - + + + URI handling + URI håndtering + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI kunne ikke tolkes! Dette kan forårsakes av en ugyldig CasinoCoin-adresse eller feil i URI-parametere. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Lommeboken er <b>kryptert</b> og for tiden <b>ulåst</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Lommeboken er <b>kryptert</b> og for tiden <b>låst</b> - - Backup Wallet - Sikkerhetskopiér Lommebok - - - - Wallet Data (*.dat) - Lommeboksdata (*.dat) - - - - Backup Failed - Sikkerhetskopiering feilet - - - - There was an error trying to save the wallet data to the new location. - En feil oppstod ved lagring av lommebok til nytt sted - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + En fatal feil har inntruffet. Det er ikke trygt å fortsette og CasinoCoin må derfor avslutte. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Visning - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Velg standard underenhet som skal vises i grensesnittet og ved sending av mynter - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Nettverksvarsel EditAddressDialog - + Edit Address Rediger adresse - + &Label &Merkelapp - + The label associated with this address book entry Merkelappen koblet til denne adressen i adresseboken - + &Address &Adresse - + The address associated with this address book entry. This can only be modified for sending addresses. Adressen til denne oppføringen i adresseboken. Denne kan kun endres for utsendingsadresser. - + New receiving address Ny mottaksadresse - + New sending address Ny utsendingsadresse - + Edit receiving address Rediger mottaksadresse - + Edit sending address Rediger utsendingsadresse - + The entered address "%1" is already in the address book. Den oppgitte adressen "%1" er allerede i adresseboken. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Den angitte adressed "%1" er ikke en gyldig CasinoCoin-adresse. - + Could not unlock wallet. Kunne ikke låse opp lommeboken. - + New key generation failed. Generering av ny nøkkel feilet. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versjon - + Usage: Bruk: - - options - + + command-line options + kommandolinjevalg - + UI options - + valg i brukergrensesnitt - + Set language, for example "de_DE" (default: system locale) Sett språk, for eksempel "nb_NO" (standardverdi: fra operativsystem) - + Start minimized Start minimert - + Show splash screen on startup (default: 1) Vis splashskjerm ved oppstart (standardverdi: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Innstillinger + + + + &Main + &Hoved + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Betal transaksjons&gebyr - - Main - Hoved + + Automatically start CasinoCoin after logging in to the system. + Start CasinoCoin automatisk etter innlogging. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Valgfritt transaksjonsgebyr per kB som sikrer at dine transaksjoner blir raskt prosessert. De fleste transaksjoner er 1 kB. Et gebyr på 0.01 er anbefalt. + + &Start CasinoCoin on system login + &Start CasinoCoin ved systeminnlogging - - &Start Bitcoin on system login + + Reset all client options to default. - - Automatically start Bitcoin after logging in to the system + + &Reset Options - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + &Nettverk - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Du kan signere meldinger med dine adresser for å bevise at du eier dem. Ikke signér vage meldinger da phishing-angrep kan prøve å lure deg til å signere din identitet over til andre. Signér kun fullt detaljerte utsagn som du er enig i. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Åpne automatisk CasinoCoin klientporten på ruteren. Dette virker kun om din ruter støtter UPnP og dette er påslått. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adressen meldingen skal signeres med (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Velg adresse fra adresseboken - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Lim inn adresse fra utklippstavlen - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Skriv inn meldingen du vil signere her - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Klikk "Signér Melding" for signatur - - - - Sign a message to prove you own this address - Signér en melding for å bevise at du eier denne adressen - - - - &Sign Message - &Signér Melding - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Skriv inn en Bitcoin adresse (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Feil ved signering - - - - %1 is not a valid address. - %1 er ikke en gyldig adresse - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Privat nøkkel for %1 er ikke tilgjengelig. - - - - Sign failed - Signering feilet - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Sett opp port vha. &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Åpne automatisk Bitcoin klientporten på ruteren. Dette virker kun om din ruter støtter UPnP og dette er påslått. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Koble til CasinoCoin-nettverket gjennom en SOCKS proxy (f.eks. ved tilkobling gjennom Tor). - - &Connect through SOCKS4 proxy: - &Koble til gjennom SOCKS4 proxy: + + &Connect through SOCKS proxy: + &Koble til gjenom SOCKS proxy: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Koble til Bitcoin nettverket gjennom en SOCKS4 mellomtjener (f.eks. for tilkobling gjennom Tor) - - - + Proxy &IP: - + Proxy &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) IP-adresse for mellomtjener (f.eks. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Port for mellomtjener (f.eks. 1234) + + &Port: + &Port: - - - OptionsDialog - - Options - Innstillinger + + Port of the proxy (e.g. 9050) + Proxyens port (f.eks. 9050) + + + + SOCKS &Version: + SOCKS &Versjon: + + + + SOCKS version of the proxy (e.g. 5) + Proxyens SOCKS versjon (f.eks. 5) + + + + &Window + &Vindu + + + + Show only a tray icon after minimizing the window. + Vis kun ikon i systemkurv etter minimering av vinduet. + + + + &Minimize to the tray instead of the taskbar + &Minimer til systemkurv istedenfor oppgavelinjen + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimerer vinduet istedenfor å avslutte applikasjonen når vinduet lukkes. Når dette er slått på avsluttes applikasjonen kun ved å velge avslutt i menyen. + + + + M&inimize on close + M&inimer ved lukking + + + + &Display + &Visning + + + + User Interface &language: + &Språk for brukergrensesnitt + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Språket for brukergrensesnittet kan settes her. Innstillingen trer i kraft ved omstart av CasinoCoin. + + + + &Unit to show amounts in: + &Enhet for visning av beløper: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Velg standard delt enhet for visning i grensesnittet og for sending av casinocoins. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Om CasinoCoin-adresser skal vises i transaksjonslisten eller ikke. + + + + &Display addresses in transaction list + &Vis adresser i transaksjonslisten + + + + &OK + &OK + + + + &Cancel + &Avbryt + + + + &Apply + &Bruk + + + + default + standardverdi + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Advarsel + + + + + This setting will take effect after restarting CasinoCoin. + Denne innstillingen trer i kraft etter omstart av CasinoCoin. + + + + The supplied proxy address is invalid. + Angitt proxyadresse er ugyldig. OverviewPage - + Form Skjema - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Informasjonen som vises kan være foreldet. Din lommebok synkroniseres automatisk med CasinoCoin-nettverket etter at tilkobling er opprettet, men denne prosessen er ikke ferdig enda. - + Balance: Saldo: - - Number of transactions: - Antall transaksjoner: - - - + Unconfirmed: Ubekreftet - + Wallet Lommebok - + + Immature: + Umoden: + + + + Mined balance that has not yet matured + Minet saldo har ikke modnet enda + + + <b>Recent transactions</b> <b>Siste transaksjoner</b> - + Your current balance Din nåværende saldo - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Totalt antall ubekreftede transaksjoner som ikke telles med i saldo enda - - Total number of transactions in wallet - Totalt antall transaksjoner i lommeboken - - - - + + out of sync - + ute av synk + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Kan ikke starte casinocoin: klikk-og-betal håndterer QRCodeDialog - + QR Code Dialog - + Dialog for QR Kode - - QR Code - QR Kode - - - + Request Payment Etterspør Betaling - + Amount: Beløp: - - BTC - BTC - - - + Label: Merkelapp: - + Message: Melding: - + &Save As... &Lagre Som... - + Error encoding URI into QR Code. - + Feil ved koding av URI i QR kode. - + + The entered amount is invalid, please check. + Angitt beløp er ugyldig. + + + Resulting URI too long, try to reduce the text for label / message. Resulterende URI for lang, prøv å redusere teksten for merkelapp / melding. - + Save QR Code - + Lagre QR Kode - + PNG Images (*.png) PNG bilder (*.png) @@ -1122,453 +1135,713 @@ Adresse: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Klientnavn - - - - - - - - - + + + + + + + + + + N/A - + - - + Client version - + Klientversjon - + &Information - + &Informasjon - - Client - + + Using OpenSSL version + Bruker OpenSSL versjon - + Startup time - + Oppstartstidspunkt - + Network - + Nettverk - + Number of connections - + Antall tilkoblinger - + On testnet - + På testnett - + Block chain - + Blokkjeden - + Current number of blocks - + Nåværende antall blokker - + Estimated total blocks - + Estimert totalt antall blokker - + Last block time - + Tidspunkt for siste blokk - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Åpne - + + Command-line options + Kommandolinjevalg + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Vis CasinoCoin-Qt hjelpemelding for å få en liste med mulige kommandolinjevalg. + + + + &Show + &Vis + + + &Console - + &Konsoll - + Build date - + Byggedato - + + CasinoCoin - Debug window + CasinoCoin - vindu for feilsøk + + + + CasinoCoin Core + CasinoCoin Kjerne + + + + Debug log file + Loggfil for feilsøk + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Åpne CasinoCoin loggfil for feilsøk fra datamappen. Dette kan ta noen sekunder for store loggfiler. + + + Clear console - + Tøm konsoll - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Velkommen til CasinoCoin RPC konsoll. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Bruk opp og ned pil for å navigere historikken, og <b>Ctrl-L</b> for å tømme skjermen. - + Type <b>help</b> for an overview of available commands. - + Skriv <b>help</b> for en oversikt over kommandoer. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Send Bitcoins + Send CasinoCoins - + Send to multiple recipients at once Send til flere enn én mottaker - - &Add Recipient - + + Add &Recipient + &Legg til Mottaker - + Remove all transaction fields Fjern alle transaksjonsfelter - + Clear &All - + Fjern &Alt - + Balance: Saldo: - + 123.456 BTC 123.456 BTC - + Confirm the send action Bekreft sending - - &Send - &Send + + S&end + S&end - + <b>%1</b> to %2 (%3) <b>%1</b> til %2 (%3) - + Confirm send coins - Bekreft sending av bitcoins + Bekreft sending av casinocoins - + Are you sure you want to send %1? Er du sikker på at du vil sende %1? - + and og - - The recepient address is not valid, please recheck. - Mottaksadressen er ugyldig, prøv igjen. + + The recipient address is not valid, please recheck. + Adresse for mottaker er ugyldig. - + The amount to pay must be larger than 0. Beløpen som skal betales må være over 0. - + The amount exceeds your balance. - + Beløpet overstiger saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + Totalbeløpet overstiger saldo etter at %1 transaksjonsgebyr er lagt til. - + Duplicate address found, can only send to each address once per send operation. - + Duplikate adresser funnet. Kan bare sende én gang til hver adresse per operasjon. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Feil: Opprettelse av transaksjon feilet - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Feil: Transaksjonen ble avvist. Dette kan skje om noe av beløpet allerede var brukt, f.eks. hvis du kopierte wallet.dat og noen casinocoins ble brukt i kopien men ikke ble markert som brukt her. SendCoinsEntry - + Form Skjema - + A&mount: &Beløp: - + Pay &To: Betal &Til: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adressen betalingen skal sendes til (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Skriv inn en merkelapp for denne adressen for å legge den til i din adressebok - + &Label: &Merkelapp: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adressen betalingen skal sendes til (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Velg adresse fra adresseboken - + Alt+A Alt+A - + Paste address from clipboard Lim inn adresse fra utklippstavlen - + Alt+P Alt+P - + Remove this recipient Fjern denne mottakeren - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Skriv inn en Bitcoin adresse (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Skriv inn en CasinoCoin adresse (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signaturer - Signer / Verifiser en melding + + + + &Sign Message + &Signér Melding + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Du kan signere meldinger med dine adresser for å bevise at du eier dem. Ikke signér vage meldinger da phishing-angrep kan prøve å lure deg til å signere din identitet over til andre. Signér kun fullt detaljerte utsagn som du er enig i. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adressen for signering av meldingen (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Velg en adresse fra adresseboken + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Lim inn adresse fra utklippstavlen + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Skriv inn meldingen du vil signere her + + + + Signature + + + + + Copy the current signature to the system clipboard + Kopier valgt signatur til utklippstavle + + + + Sign the message to prove you own this CasinoCoin address + Signer meldingen for å bevise at du eier denne CasinoCoin-adressen + + + + Sign &Message + + + + + Reset all sign message fields + Tilbakestill alle felter for meldingssignering + + + + + Clear &All + Fjern &Alt + + + + &Verify Message + &Verifiser Melding + + + + Enter the signing 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. + Angi adresse for signering, melding (vær sikker på at du kopierer linjeskift, mellomrom, tab, etc. helt nøyaktig) og signatur under for å verifisere meldingen. Vær forsiktig med at du ikke gir signaturen mer betydning enn det som faktisk står i meldingen, for å unngå å bli lurt av såkalte "man-in-the-middle" angrep. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adressen meldingen var signert med (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verifiser meldingen for å være sikker på at den ble signert av den angitte CasinoCoin-adressen + + + + Verify &Message + + + + + Reset all verify message fields + Tilbakestill alle felter for meldingsverifikasjon + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Skriv inn en CasinoCoin adresse (f.eks. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Klikk "Signer Melding" for å generere signatur + + + + Enter CasinoCoin signature + Angi CasinoCoin signatur + + + + + The entered address is invalid. + Angitt adresse er ugyldig. + + + + + + + Please check the address and try again. + Vennligst sjekk adressen og prøv igjen. + + + + + The entered address does not refer to a key. + Angitt adresse refererer ikke til en nøkkel. + + + + Wallet unlock was cancelled. + Opplåsing av lommebok ble avbrutt. + + + + Private key for the entered address is not available. + Privat nøkkel for den angitte adressen er ikke tilgjengelig. + + + + Message signing failed. + Signering av melding feilet. + + + + Message signed. + Melding signert. + + + + The signature could not be decoded. + Signaturen kunne ikke dekodes. + + + + + Please check the signature and try again. + Vennligst sjekk signaturen og prøv igjen. + + + + The signature did not match the message digest. + Signaturen passer ikke til meldingen. + + + + Message verification failed. + Verifikasjon av melding feilet. + + + + Message verified. + Melding verifisert. + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnett] TransactionDesc - - Open for %1 blocks - Åpen for %1 blokker - - - + Open until %1 Åpen til %1 - - %1/offline? - %1/frakoblet? + + %1/offline + %1/frakoblet - + %1/unconfirmed %1/ubekreftet - + %1 confirmations %1 bekreftelser - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , kringkast gjennom %n node, kringkast gjennom %n noder - + + Date + Dato + + + + Source + Kilde + + + + Generated + Generert + + + + + From + Fra + + + + + + To + Til + + + + + own address + egen adresse + + + + label + merkelapp + + + + + + + + Credit + Kredit + + + + matures in %n more block(s) + blir moden om %n blokkblir moden om %n blokker + + + + not accepted + ikke akseptert + + + + + + + Debit + Debet + + + + Transaction fee + Transaksjonsgebyr + + + + Net amount + Nettobeløp + + + + Message + Melding + + + + Comment + Kommentar + + + + Transaction ID + Transaksjons-ID + + + + Generated coins must mature 120 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. + Genererte casinocoins må modnes 120 blokker før de kan brukes. Da du genererte denne blokken ble den kringkastet til nettverket for å legges til i blokkjeden. Hvis den ikke kommer inn i kjeden får den tilstanden "ikke akseptert" og vil ikke kunne brukes. Dette skjer noen ganger hvis en annen node genererer en blokk noen sekunder fra din. + + + + Debug information + Informasjon for feilsøk + + + + Transaction + Transaksjon + + + + Inputs + Inndata + + + + Amount + Beløp + + + + true + sann + + + + false + usann + + + , has not been successfully broadcast yet , har ikke blitt kringkastet uten problemer enda. - - - , broadcast through %1 node - , kringkast gjennom %1 node + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , kringkast gjennom %1 noder - - - - <b>Date:</b> - <b>Dato:</b> - - - - <b>Source:</b> Generated<br> - <b>Kilde:</b> Generert<br> - - - - - <b>From:</b> - <b>Fra:</b> - - - + unknown ukjent - - - - - <b>To:</b> - <b>Til:</b> - - - - (yours, label: - (din, merkelapp: - - - - (yours) - (din) - - - - - - - <b>Credit:</b> - <b>Kredit:</b> - - - - (%1 matures in %2 more blocks) - (%1 modnes om %2 flere blokker) - - - - (not accepted) - (ikke akseptert) - - - - - - <b>Debit:</b> - <b>Debet:</b> - - - - <b>Transaction fee:</b> - <b>Transaksjonsgebyr:</b> - - - - <b>Net amount:</b> - <b>Nettobeløp:</b> - - - - Message: - Melding: - - - - Comment: - Kommentar: - - - - Transaction ID: - Transaksjons-ID: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Genererte mynter må vente 120 blokker før de kan brukes. Da du genererte denne blokken ble den kringkastet på nettverket for å bli lagt til i kjeden av blokker. Hvis den ikke kommer med i kjeden vil den endre seg til "ikke akseptert og pengene vil ikke kunne brukes. Dette vil noen ganger skje hvis en annen node genererer en blokk noen sekunder i tid fra din egen. - TransactionDescDialog - + Transaction details Transaksjonsdetaljer - + This pane shows a detailed description of the transaction Her vises en detaljert beskrivelse av transaksjonen @@ -1576,117 +1849,117 @@ Adresse: %4 TransactionTableModel - + Date Dato - + Type Type - + Address Adresse - + Amount Beløp - - Open for %n block(s) - Åpen for %n blokkÅpen for %n blokker + + Open for %n more block(s) + - + Open until %1 Åpen til %1 - + Offline (%1 confirmations) Frakoblet (%1 bekreftelser) - + Unconfirmed (%1 of %2 confirmations) Ubekreftet (%1 av %2 bekreftelser) - + Confirmed (%1 confirmations) Bekreftet (%1 bekreftelser) - - Mined balance will be available in %n more blocks - Utvunnet saldo vil bli tilgjengelig om %n blokkUtvunnet saldo vil bli tilgjengelig om %n blokker + + Mined balance will be available when it matures in %n more block(s) + Minet saldo blir tilgjengelig når den modner om %n blokkMinet saldo blir tilgjengelig når den modner om %n blokker - + This block was not received by any other nodes and will probably not be accepted! Denne blokken har ikke blitt mottatt av noen andre noder og vil sannsynligvis ikke bli akseptert! - + Generated but not accepted Generert men ikke akseptert - + Received with Mottatt med - + Received from Mottatt fra - + Sent to Sendt til - + Payment to yourself Betaling til deg selv - + Mined Utvunnet - + (n/a) - - + Transaction status. Hover over this field to show number of confirmations. Transaksjonsstatus. Hold muspekeren over dette feltet for å se antall bekreftelser. - + Date and time that the transaction was received. Dato og tid for da transaksjonen ble mottat. - + Type of transaction. Type transaksjon. - + Destination address of transaction. Mottaksadresse for transaksjonen - + Amount removed from or added to balance. Beløp fjernet eller lagt til saldo. @@ -1694,817 +1967,966 @@ Adresse: %4 TransactionView - - + + All Alle - + Today I dag - + This week Denne uken - + This month Denne måneden - + Last month Forrige måned - + This year Dette året - + Range... Intervall... - + Received with Mottatt med - + Sent to Sendt til - + To yourself Til deg selv - + Mined Utvunnet - + Other Andre - + Enter address or label to search Skriv inn adresse eller merkelapp for søk - + Min amount Minimumsbeløp - + Copy address Kopier adresse - + Copy label Kopier merkelapp - + Copy amount Kopiér beløp - + + Copy transaction ID + Kopier transaksjons-ID + + + Edit label Rediger merkelapp - + Show transaction details - + Vis transaksjonsdetaljer - + Export Transaction Data Eksporter transaksjonsdata - + Comma separated file (*.csv) Kommaseparert fil (*.csv) - + Confirmed Bekreftet - + Date Dato - + Type Type - + Label Merkelapp - + Address Adresse - + Amount Beløp - + ID ID - + Error exporting Feil ved eksport - + Could not write to file %1. Kunne ikke skrive til filen %1. - + Range: Intervall: - + to til - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopier den valgte adressen til systemets utklippstavle - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Sender... + + Send Coins + Send CasinoCoins - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &Minimer til systemkurv istedenfor oppgavelinjen + + Export the data in the current tab to a file + Eksporter data fra nåværende fane til fil - - Show only a tray icon after minimizing the window - Vis kun ikon i systemkurv etter minimering av vinduet + + Backup Wallet + Sikkerhetskopier lommebok - - M&inimize on close - + + Wallet Data (*.dat) + Lommebokdata (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimerer vinduet istedenfor å avslutte applikasjonen når vinduet lukkes. Når dette er slått på avsluttes applikasjonen kun ved å velge avslutt i menyen. + + Backup Failed + Sikkerhetskopiering feilet + + + + There was an error trying to save the wallet data to the new location. + En feil oppstod under lagringen av lommeboken til den nye plasseringen. + + + + Backup Successful + Sikkerhetskopiering fullført + + + + The wallet data was successfully saved to the new location. + Lommebokdata ble lagret til den nye plasseringen. bitcoin-core - - Bitcoin version - Bitcoin versjon + + CasinoCoin version + CasinoCoin versjon - + Usage: Bruk: - - Send command to -server or bitcoind - Send kommando til -server eller bitcoind + + Send command to -server or casinocoind + Send kommando til -server eller casinocoind - + List commands List opp kommandoer - + Get help for a command Vis hjelpetekst for en kommando - + Options: Innstillinger: - - Specify configuration file (default: bitcoin.conf) - Angi konfigurasjonsfil (standardverdi: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Angi konfigurasjonsfil (standardverdi: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Angi pid-fil (standardverdi: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Angi pid-fil (standardverdi: casinocoind.pid) - - Generate coins - Generér bitcoins - - - - Don't generate coins - Ikke generér bitcoins - - - + Specify data directory Angi mappe for datafiler - + Set database cache size in megabytes (default: 25) Sett størrelse på mellomlager for database i megabytes (standardverdi: 25) - - Set database disk log size in megabytes (default: 100) - Sett størrelse på disklogg for database i megabytes (standardverdi: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Lytt etter tilkoblinger på <port> (standardverdi: 47950 eller testnet: 17950) - - Specify connection timeout (in milliseconds) - Angi tidsavbrudd for forbindelse (i millisekunder) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Lytt etter tilkoblinger på <port> (standardverdi: 8333 eller testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Hold maks <n> koblinger åpne til andre noder (standardverdi: 125) - - Connect only to the specified node - Koble kun til angitt node - - - + Connect to a node to retrieve peer addresses, and disconnect - + Koble til node for å hente adresser til andre noder, koble så fra igjen - + Specify your own public address - + Angi din egen offentlige adresse - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Grenseverdi for å koble fra noder med dårlig oppførsel (standardverdi: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Antall sekunder noder med dårlig oppførsel hindres fra å koble til på nytt (standardverdi: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maksimum mottaksbuffer per tilkobling, <n>*1000 bytes (standardverdi: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + En feil oppstod ved opprettelse av RPC port %u for lytting: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maksimum sendebuffer per tilkobling, <n>*1000 bytes (standardverdi: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Lytt etter JSON-RPC tilkoblinger på <port> (standardverdi: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Ta imot kommandolinje- og JSON-RPC-kommandoer - + Run in the background as a daemon and accept commands Kjør i bakgrunnen som daemon og ta imot kommandoer - + Use the test network Bruk testnettverket - - Output extra debugging information - Gi ut ekstra debuginformasjon + + Accept connections from outside (default: 1 if no -proxy or -connect) + Ta imot tilkoblinger fra utsiden (standardverdi: 1 hvis uten -proxy eller -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, du må angi rpcpassord i konfigurasjonsfilen. +%s +Det anbefales at du bruker det følgende tilfeldige passordet: +rpcbruker=casinocoinrpc +rpcpassord=%s +(du behøver ikke å huske passordet) +Brukernavnet og passordet MÅ IKKE være like. +Om filen ikke eksisterer, opprett den nå med eier-kun-les filrettigheter. +Det er også anbefalt at å sette varselsmelding slik du får melding om problemer. +For eksempel: varselmelding=echo %%s | mail -s "CasinoCoin varsel" admin@foo.com + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + En feil oppstod under oppsettet av RPC port %u for IPv6, tilbakestilles til IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Bind til angitt adresse. Bruk [vertsmaskin]:port notasjon for IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Kjør kommando når relevant varsel blir mottatt (%s i cmd er erstattet med TxID) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Kjør kommando når en lommeboktransaksjon endres (%s i cmd er erstattet med TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Sett maks størrelse for transaksjoner med høy prioritet / lavt gebyr, i bytes (standardverdi: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Advarsel: -paytxfee er satt veldig høyt! Dette er transaksjonsgebyret du betaler når du sender transaksjoner. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Advarsel: Viste transaksjoner kan være feil! Du, eller andre noder, kan trenge en oppgradering. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Advarsel: Vennligst undersøk at din datamaskin har riktig dato og klokkeslett! Hvis klokken er stilt feil vil ikke CasinoCoin fungere riktig. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + Valg for opprettelse av blokker: + + + + Connect only to the specified node(s) + Koble kun til angitt(e) node(r) + + + + Corrupted block database detected + Oppdaget korrupt blokkdatabase + + + + Discover own IP address (default: 1 when listening and no -externalip) + Oppdag egen IP-adresse (standardverdi: 1 ved lytting og uten -externalip) + + + + Do you want to rebuild the block database now? + Ønsker du å gjenopprette blokkdatabasen nå? + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + Feil under oppstart av lommebokdatabasemiljø %s! + + + + Error loading block database + + + + + Error opening block database + Feil under åpning av blokkdatabase + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + Kunne ikke lytte på noen port. Bruk -listen=0 hvis det er dette du vil. + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + Finn andre noder gjennom DNS-oppslag (standardverdi: 1 med mindre -connect er oppgit) + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + Gjenopprett blokkjedeindex fra blk000??.dat filer + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + Verifiserer blokker... + + + + Verifying wallet... + Verifiserer lommebok... + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Ugyldig -tor adresse: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maks mottaksbuffer per forbindelse, <n>*1000 bytes (standardverdi: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maks sendebuffer per forbindelse, <n>*1000 bytes (standardverdi: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Koble kun til noder i nettverket <nett> (IPv4, IPv6 eller Tor) + + + + Output extra debugging information. Implies all other -debug* options + Skriv ekstra informasjon for feilsøk. Medfører at alle -debug* valg tas med + + + + Output extra network debugging information + Skriv ekstra informasjon for feilsøk av nettverk + + + Prepend debug output with timestamp Sett tidsstempel på debugmeldinger - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL valg: (se CasinoCoin Wiki for instruksjoner for oppsett av SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Velg versjon av socks proxy (4-5, standardverdi 5) + + + Send trace/debug info to console instead of debug.log file Send spor/debug informasjon til konsollet istedenfor debug.log filen - + Send trace/debug info to debugger Send spor/debug informasjon til debugger - + + Set maximum block size in bytes (default: 250000) + Sett maks blokkstørrelse i bytes (standardverdi: 250000) + + + + Set minimum block size in bytes (default: 0) + Sett minimum blokkstørrelse i bytes (standardverdi: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Krymp debug.log filen når klienten starter (standardverdi: 1 hvis uten -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Angi tidsavbrudd for forbindelse i millisekunder (standardverdi: 5000) + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Bruk UPnP for lytteport (standardverdi: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Bruk UPnP for lytteport (standardverdi: 1 ved lytting) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Bruk en proxy for å nå skjulte tor tjenester (standardverdi: samme som -proxy) + + + Username for JSON-RPC connections Brukernavn for JSON-RPC forbindelser - + + Warning + + + + + Warning: This version is obsolete, upgrade required! + Advarsel: Denne versjonen er foreldet, oppgradering kreves! + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + Password for JSON-RPC connections Passord for JSON-RPC forbindelser - - Listen for JSON-RPC connections on <port> (default: 8332) - Lytt etter JSON-RPC tilkoblinger på <port> (standardverdi: 8332) - - - + Allow JSON-RPC connections from specified IP address Tillat JSON-RPC tilkoblinger fra angitt IP-adresse - + Send commands to node running on <ip> (default: 127.0.0.1) Send kommandoer til node på <ip> (standardverdi: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Eksekvér kommando når beste blokk endrer seg (%s i kommandoen erstattes med blokkens hash) - + Upgrade wallet to latest format Oppgradér lommebok til nyeste format - + Set key pool size to <n> (default: 100) Angi størrelse på nøkkel-lager til <n> (standardverdi: 100) - + Rescan the block chain for missing wallet transactions Se gjennom blokk-kjeden etter manglende lommeboktransaksjoner - - How many blocks to check at startup (default: 2500, 0 = all) - Hvor mange blokker som skal sjekkes ved oppstart (standardverdi: 2500, 0 = alle) - - - - How thorough the block verification is (0-6, default: 1) - Hvor grundig verifisering av blokker gjøres (0-6, standardverdi: 1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL innstillinger: (se Bitcoin Wiki for instruksjoner om SSL oppsett) - - - + Use OpenSSL (https) for JSON-RPC connections Bruk OpenSSL (https) for JSON-RPC forbindelser - + Server certificate file (default: server.cert) Servers sertifikat (standardverdi: server.cert) - + Server private key (default: server.pem) Servers private nøkkel (standardverdi: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akseptable krypteringsmetoder (standardverdi: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Denne hjelpemeldingen - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Kunne ikke låse datamappen %s. Bitcoin kjører sannsynligvis allerede. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Kan ikke binde til %s på denne datamaskinen (bind returnerte feil %d, %s) - + Connect through socks proxy - + Koble til gjennom socks proxy - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Tillat DNS oppslag for -addnode, -seednode og -connect - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Laster adresser... - - Error loading blkindex.dat - Feil ved lasting av blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Feil ved lasting av wallet.dat: Lommeboken er skadet - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Feil ved lasting av wallet.dat: Lommeboken krever en nyere versjon av Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Feil ved lasting av wallet.dat: Lommeboken krever en nyere versjon av CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Lommeboken måtte skrives om: start Bitcoin på nytt for å fullføre + + Wallet needed to be rewritten: restart CasinoCoin to complete + Lommeboken måtte skrives om: start CasinoCoin på nytt for å fullføre - + Error loading wallet.dat Feil ved lasting av wallet.dat - + Invalid -proxy address: '%s' - + Ugyldig -proxy adresse: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Ukjent nettverk angitt i -onlynet '%s' - + Unknown -socks proxy version requested: %i - + Ukjent -socks proxy versjon angitt: %i - + Cannot resolve -bind address: '%s' - + Kunne ikke slå opp -bind adresse: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Kunne ikke slå opp -externalip adresse: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Ugyldig beløp for -paytxfee=<beløp>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Feil: Lommebok låst, kan ikke opprette transaksjon - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Feil: Denne transaksjonen krever et gebyr på minst %s pga. beløpet, kompleksiteten, eller bruk av nylig mottatte midler - - - - Error: Transaction creation failed - Feil: Opprettelse av transaksjon feilet - - - - Sending... - Sender... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Feil: Transaksjonen ble avvist. Dette kan skje hvis noen av myntene i lommeboken allerede var brukt, f.eks. hvis du kopierte wallet.dat og mynter ble brukt i kopien uten å bli markert brukt her. - - - + Invalid amount Ugyldig beløp - + Insufficient funds Utilstrekkelige midler - + Loading block index... Laster blokkindeks... - + Add a node to connect to and attempt to keep the connection open Legg til node for tilkobling og hold forbindelsen åpen - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Kan ikke binde til %s på denne datamaskinen. Sannsynligvis kjører CasinoCoin allerede. - - Find peers using internet relay chat (default: 0) - Finn andre noder via internet relay chat (standardverdi: 0) - - - - Accept connections from outside (default: 1) - Ta imot innkommende forbindelser fra nettet (standardverdi: 1) - - - - Find peers using DNS lookup (default: 1) - Finn andre noder gjennom DNS-oppslag (standardverdi: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Bruk Universal Plug and Play for å sette opp lytteporten (standardverdi :1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Bruk Universal Plug and Play for å sette opp lytteporten (standardverdi :0) - - - + Fee per KB to add to transactions you send Gebyr per KB for transaksjoner du sender - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Laster lommebok... - + Cannot downgrade wallet Kan ikke nedgradere lommebok - - Cannot initialize keypool - Kan ikke initialisere nøkkellager - - - + Cannot write default address Kan ikke skrive standardadresse - + Rescanning... Leser gjennom... - + Done loading Ferdig med lasting - + To use the %s option For å bruke %s opsjonen - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, du må sette et rpcpassord i konfigurasjonsfilen: - %s -Det anbefales at du bruker følgende tilfeldige passord: -rpcuser=bitcoinrpc -rpcpassword=%s -(du trenger ikke huske dette passordet) -Hvis filen ikke finnes, opprett den med leserettighet kun for eier av filen. - - - - + Error Feil - - An error occured while setting up the RPC port %i for listening: %s - En feil oppstod ved oppsett av RPC port %i for lytting: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2512,10 +2934,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Hvis filen ikke finnes, opprett den med leserettighet kun for eier av filen. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Advarsel: Vennligst sjekk at dato og klokke er riktig innstilt på datamaskinen. Hvis klokken er feil vil ikke Bitcoin fungere ordentlig. - - \ No newline at end of file + diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 8ffa769..2dd97a0 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -3,123 +3,160 @@ AboutDialog - - About Bitcoin - Over Bitcoin - + + About CasinoCoin + Over CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versie + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versie - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Ontwikkelaars - + Dit is experimentele software. -Gedistribueerd onder de MIT/X11 software licentie, zie het bijgevoegde bestand license.txt of http://www.opensource.org/licenses/mit-license.php. +Gedistribueerd onder de MIT/X11 software licentie, zie het bijgevoegde bestand COPYING of http://www.opensource.org/licenses/mit-license.php. Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in de OpenSSL Toolkit (http://www.openssl.org/) en cryptografische software gemaakt door Eric Young (eay@cryptsoft.com) en UPnP software geschreven door Thomas Bernard. + + + Copyright + Auteursrecht + + + + The CasinoCoin developers + De CasinoCoin-ontwikkelaars + AddressBookPage - + Address Book Adresboek - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Dit zijn uw Bitcoin-adressen om betalingen te ontvangen. U kunt er voor kiezen om een adres aan te maken voor elke afzender. Op deze manier kunt u bijhouden wie al aan u betaald heeft. - - - + Double-click to edit address or label Dubbelklik om adres of label te wijzigen - + Create a new address Maak een nieuw adres aan - + Copy the currently selected address to the system clipboard Kopieer het huidig geselecteerde adres naar het klembord - + &New Address &Nieuw Adres - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Dit zijn uw CasinoCoinadressen om betalingen mee te ontvangen. U kunt er voor kiezen om een uniek adres aan te maken voor elke afzender. Op deze manier kunt u bijhouden wie al aan u betaald heeft. + + + &Copy Address &Kopiëer Adres - + Show &QR Code Toon &QR-Code - - Sign a message to prove you own this address - Onderteken een bericht om te bewijzen dat u dit adres bezit + + Sign a message to prove you own a CasinoCoin address + Onderteken een bericht om te bewijzen dat u een bepaald CasinoCoinadres bezit - - &Sign Message + + Sign &Message &Onderteken Bericht - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Verwijder het huidige geselecteerde adres van de lijst. Alleen zend-adressen kunnen verwijderd worden, niet uw ontvangstadressen. + + Delete the currently selected address from the list + Verwijder het geselecteerde adres van de lijst - + + Export the data in the current tab to a file + Exporteer de data in de huidige tab naar een bestand + + + + &Export + &Exporteer + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Controleer een bericht om te verifiëren dat het gespecificeerde CasinoCoinadres het bericht heeft ondertekend. + + + + &Verify Message + &Verifiëer Bericht + + + &Delete &Verwijder - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Dit zijn uw CasinoCoinadressen om betalingen mee te verzenden. Check altijd het bedrag en het ontvangende adres voordat u uw casinocoins verzendt. + + + Copy &Label Kopiëer &Label - + &Edit &Bewerk - + + Send &Coins + Verstuur &Coins + + + Export Address Book Data Exporteer Gegevens van het Adresboek - + Comma separated file (*.csv) Kommagescheiden bestand (*.csv) - + Error exporting Fout bij exporteren - + Could not write to file %1. Kon niet schrijven naar bestand %1. @@ -127,17 +164,17 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d AddressTableModel - + Label Label - + Address Adres - + (no label) (geen label) @@ -145,432 +182,460 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d AskPassphraseDialog - + Passphrase Dialog Wachtwoorddialoogscherm - + Enter passphrase - Huidig wachtwoord + Voer wachtwoord in - + New passphrase - Nieuwe wachtwoord + Nieuw wachtwoord - + Repeat new passphrase Herhaal wachtwoord - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Vul een nieuw wachtwoord in voor uw portemonnee. <br/> Gebruik een wachtwoord van <b>10 of meer lukrake karakters</b>, of <b> acht of meer woorden</b> . - + Encrypt wallet Versleutel portemonnee - + This operation needs your wallet passphrase to unlock the wallet. Deze operatie vereist uw portemonneewachtwoord om de portemonnee te openen. - + Unlock wallet Open portemonnee - + This operation needs your wallet passphrase to decrypt the wallet. Deze operatie vereist uw portemonneewachtwoord om de portemonnee te ontsleutelen - + Decrypt wallet Ontsleutel portemonnee - + Change passphrase Wijzig wachtwoord - + Enter the old and new passphrase to the wallet. Vul uw oude en nieuwe portemonneewachtwoord in. - + Confirm wallet encryption Bevestig versleuteling van de portemonnee - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - WAARSCHUWING: Wanneer uw portemonnee wordt versleuteld en u verliest uw wachtwoord, dan verliest u <b>AL UW BITCOINS</b>! -Bent u er zeker van uw dat u uw portemonnee wilt versleutelen? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Waarschuwing: Als u uw portemonnee versleutelt en uw wachtwoord vergeet, zult u <b>AL UW CASINOCOINS VERLIEZEN</b>! - - + + Are you sure you wish to encrypt your wallet? + Weet u zeker dat u uw portemonnee wilt versleutelen? + + + + 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. + 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. + + + + + Warning: The Caps Lock key is on! + Waarschuwing: De Caps-Lock-toets staat aan! + + + + Wallet encrypted Portemonnee versleuteld - - Bitcoin 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. - Bitcoin 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. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin 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 casinocoins stelen. - - - Warning: The Caps Lock key is on. - Waarschuwing: De Caps-Lock-toets staat aan. - - - - - - + + + + Wallet encryption failed Portemonneeversleuteling mislukt - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - Portemonneeversleuteling mislukt door een interne fout, Uw portemonnee is niet versleuteld. + Portemonneeversleuteling mislukt door een interne fout. Uw portemonnee is niet versleuteld. - - + + The supplied passphrases do not match. De opgegeven wachtwoorden komen niet overeen - + Wallet unlock failed Portemonnee openen mislukt - - - + + + The passphrase entered for the wallet decryption was incorrect. Het opgegeven wachtwoord voor de portemonnee-ontsleuteling is niet correct. - + Wallet decryption failed Portemonnee-ontsleuteling mislukt - - Wallet passphrase was succesfully changed. - Portemonneewachtwoord is succesvol gewijzigd + + Wallet passphrase was successfully changed. + Portemonneewachtwoord is met succes gewijzigd. BitcoinGUI - - Bitcoin Wallet - Bitcoin-portemonnee - - - + Sign &message... &Onderteken bericht... - - Show/Hide &Bitcoin - &Toon/Verberg Bitcoin - - - + Synchronizing with network... Synchroniseren met netwerk... - + &Overview &Overzicht - + Show general overview of wallet Toon algemeen overzicht van de portemonnee - + &Transactions &Transacties - + Browse transaction history Blader door transactieverleden - - &Address Book - &Adresboek - - - + Edit the list of stored addresses and labels Bewerk de lijst van opgeslagen adressen en labels - - &Receive coins - &Ontvang munten - - - + Show the list of addresses for receiving payments Toon lijst van adressen om betalingen mee te ontvangen - - &Send coins - &Verstuur munten - - - - Prove you control an address - Bewijs dat u een adres bezit - - - + E&xit &Afsluiten - + Quit application Programma afsluiten - - &About %1 - &Over %1 + + Show information about CasinoCoin + Laat informatie zien over CasinoCoin - - Show information about Bitcoin - Laat informatie zien over Bitcoin - - - + About &Qt Over &Qt - + Show information about Qt Toon informatie over Qt - + &Options... O&pties... - + &Encrypt Wallet... &Versleutel Portemonnee... - + &Backup Wallet... &Backup Portemonnee... - + &Change Passphrase... &Wijzig Wachtwoord - - - ~%n block(s) remaining - ~%n blok resterend~%n blokken resterend + + + Importing blocks from disk... + Blokken aan het importeren vanaf harde schijf... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - %1 van %2 blokken van transactiehistorie opgehaald (%3% klaar). + + Reindexing blocks on disk... + Bezig met herindexeren van blokken op harde schijf... - - &Export... - &Exporteer... + + Send coins to a CasinoCoin address + Verstuur munten naar een CasinoCoinadres - - Send coins to a Bitcoin address - Verstuur munten naar een Bitcoinadres + + Modify configuration options for CasinoCoin + Wijzig instellingen van CasinoCoin - - Modify configuration options for Bitcoin - Wijzig instellingen van Bitcoin - - - - Show or hide the Bitcoin window - Toon of verberg Bitcoin venster - - - - Export the data in the current tab to a file - Exporteer de data in de huidige tab naar een bestand - - - - Encrypt or decrypt wallet - Versleutel of ontsleutel portemonnee - - - + Backup wallet to another location &Backup portemonnee naar een andere locatie - + Change the passphrase used for wallet encryption - wijzig het wachtwoord voor uw portemonneversleuteling + Wijzig het wachtwoord voor uw portemonneversleuteling - + &Debug window &Debugscherm - + Open debugging and diagnostic console Open debugging en diagnostische console - + &Verify message... &Verifiëer bericht... - - Verify a message signature - Verifiëer een handtekening van een bericht + + + CasinoCoin + CasinoCoin - + + Wallet + Portemonnee + + + + &Send + &Versturen + + + + &Receive + &Ontvangen + + + + &Addresses + &Adressen + + + + &About CasinoCoin + &Over CasinoCoin + + + + &Show / Hide + &Toon / Verberg + + + + Show or hide the main Window + Toon of verberg het hoofdvenster + + + + Encrypt the private keys that belong to your wallet + Versleutel de geheime sleutels die bij uw portemonnee horen + + + + Sign messages with your CasinoCoin addresses to prove you own them + Onderteken berichten met uw CasinoCoinadressen om te bewijzen dat u deze adressen bezit + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verifiëer handtekeningen om zeker te zijn dat de berichten zijn ondertekend met de gespecificeerde CasinoCoinadressen + + + &File &Bestand - + &Settings &Instellingen - + &Help &Hulp - + Tabs toolbar Tab-werkbalk - - Actions toolbar - Actie-werkbalk - - - - + + [testnet] [testnetwerk] - - - Bitcoin client - Bitcoin client + + CasinoCoin client + CasinoCoin client - - %n active connection(s) to Bitcoin network - %n actieve connectie naar Bitcoinnetwerk%n actieve connecties naar Bitcoinnetwerk + + %n active connection(s) to CasinoCoin network + %n actieve connectie naar CasinoCoinnetwerk%n actieve connecties naar CasinoCoinnetwerk - - Downloaded %1 blocks of transaction history. - %1 blokken van transactiehistorie opgehaald. - - - - %n second(s) ago - %n seconde geleden%n seconden geleden - - - - %n minute(s) ago - %n minuut geleden%n minuten geleden - - - - %n hour(s) ago - %n uur geleden%n uur geleden - - - - %n day(s) ago - %n dag geleden%n dagen geleden + + No block source available... + Geen bron van blokken beschikbaar... - + + Processed %1 of %2 (estimated) blocks of transaction history. + %1 van %2 (geschat) blokken van de transactiehistorie verwerkt. + + + + Processed %1 blocks of transaction history. + %1 blokken van transactiehistorie verwerkt. + + + + %n hour(s) + %n uur%n uur + + + + %n day(s) + %n dag%n dagen + + + + %n week(s) + %n week%n weken + + + + %1 behind + %1 achter + + + + Last received block was generated %1 ago. + Laatst ontvangen blok was %1 geleden gegenereerd. + + + + Transactions after this will not yet be visible. + Transacties na dit moment zullen nu nog niet zichtbaar zijn. + + + + Error + Fout + + + + Warning + Waarschuwing + + + + Information + Informatie + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Deze transactie overschrijdt de groottelimiet. Om de transactie alsnog te versturen kunt u transactiekosten betalen van %1. Deze transactiekosten gaan naar de nodes die uw transactie verwerken en het helpt op deze manier bij het ondersteunen van het CasinoCoinnetwerk. Wilt u de transactiekosten betalen? + + + Up to date Bijgewerkt - + Catching up... Aan het bijwerken... - - Last received block was generated %1. - Laatst ontvangen blok is %1 gegenereerd. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Deze transactie overschrijdt de groottelimiet. Om de transactie alsnog te versturen kunt u transactiekosten betalen van %1. Deze transactiekosten gaan naar de nodes die uw transactie verwerken en het helpt op deze manier bij het ondersteunen van het netwerk. Wilt u de transactiekosten betalen? - - - + Confirm transaction fee Bevestig transactiekosten - + Sent transaction Verzonden transactie - + Incoming transaction Binnenkomende transactie - + Date: %1 Amount: %2 Type: %3 @@ -583,539 +648,485 @@ Adres: %4 - + + + URI handling + URI-behandeling + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI kan niet worden geïnterpreteerd. Dit kan komen door een ongeldig CasinoCoinadres of misvormde URI-parameters. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Portemonnee is <b>versleuteld</b> en momenteel <b>geopend</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Portemonnee is <b>versleuteld</b> en momenteel <b>gesloten</b> - - Backup Wallet - Backup Portemonnee - - - - Wallet Data (*.dat) - Portemonnee-data (*.dat) - - - - Backup Failed - Backup Mislukt - - - - There was an error trying to save the wallet data to the new location. - Er is een fout opgetreden bij het wegschrijven van de portemonnee-data naar de nieuwe locatie. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Er is een fatale fout opgetreden. Bitcoin kan niet meer veilig doorgaan en zal nu afgesloten worden. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Er is een fatale fout opgetreden. CasinoCoin kan niet meer veilig doorgaan en zal nu afgesloten worden. ClientModel - + Network Alert Netwerkwaarschuwing - - DisplayOptionsPage - - - Display - Beeldscherm - - - - default - standaard - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - De taal van de gebruikersinterface kan hier ingesteld worden. Deze instelling zal pas van kracht worden nadat Bitcoin herstart wordt. - - - - User Interface &Language: - &Taal Gebruikersinterface: - - - - &Unit to show amounts in: - &Eenheid om bedrag in te tonen: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Kies de standaard onderverdelingseenheid om weer te geven in uw programma, en voor het versturen van munten - - - - &Display addresses in transaction list - Toon &adressen in de transactielijst - - - - Whether to show Bitcoin addresses in the transaction list - Of Bitcoinadressen getoond worden in de transactielijst - - - - Warning - Waarschuwing - - - - This setting will take effect after restarting Bitcoin. - Deze instelling zal pas van kracht worden na het herstarten van Bitcoin. - - EditAddressDialog - + Edit Address Bewerk Adres - + &Label &Label - + The label associated with this address book entry Het label dat geassocieerd is met dit adres - + &Address &Adres - + The address associated with this address book entry. This can only be modified for sending addresses. - Het adres dat geassocieerd is met deze adresboek-opgave. Dit kan alleen worden veranderd voor zend-adressen. + Het adres dat geassocieerd is met deze inschrijving in het adresboek. Dit kan alleen worden veranderd voor zend-adressen. - + New receiving address Nieuw ontvangstadres - + New sending address Nieuw adres om naar te verzenden - + Edit receiving address Bewerk ontvangstadres - + Edit sending address Bewerk adres om naar te verzenden - + The entered address "%1" is already in the address book. Het opgegeven adres "%1" bestaat al in uw adresboek. - - The entered address "%1" is not a valid Bitcoin address. - Het opgegeven adres "%1" is een ongeldig Bitcoinadres + + The entered address "%1" is not a valid CasinoCoin address. + Het opgegeven adres "%1" is een ongeldig CasinoCoinadres - + Could not unlock wallet. Kon de portemonnee niet openen. - + New key generation failed. Genereren nieuwe sleutel mislukt. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version versie - + Usage: Gebruik: - - options - opties + + command-line options + commandoregel-opties - + UI options gebruikersinterfaceopties - + Set language, for example "de_DE" (default: system locale) Stel taal in, bijvoorbeeld ''de_DE" (standaard: systeeminstellingen) - + Start minimized - Geminimaliseerd starten - + Geminimaliseerd starten - + Show splash screen on startup (default: 1) Laat laadscherm zien bij het opstarten. (standaard: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Ontkoppel blok- en adresdatabases bij afsluiten. Dit betekent dat ze verplaatst kunnen worden naar een andere map, maar het vertraagt het afsluiten. De portemonnee wordt altijd ontkoppeld. + + Options + Opties - + + &Main + &Algemeen + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optionele transactiekosten per kB. Transactiekosten helpen ervoor te zorgen dat uw transacties snel verwerkt worden. De meeste transacties zijn 1kB. + + + Pay transaction &fee Betaal &transactiekosten - - Main - Algemeen + + Automatically start CasinoCoin after logging in to the system. + Start CasinoCoin automatisch na inloggen in het systeem - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Optionele transactiekosten per kB die helpen om uw transacties snel te verwerken. De meeste transacties zijn 1 kB. Transactiekosten van 0,01 wordt aangeraden + + &Start CasinoCoin on system login + Start &CasinoCoin bij het inloggen in het systeem - - &Start Bitcoin on system login - &Start Bitcoin bij het inloggen in het systeem + + Reset all client options to default. + Reset alle clientopties naar de standaardinstellingen. - - Automatically start Bitcoin after logging in to the system - Start Bitcoin automatisch na inloggen in het systeem + + &Reset Options + &Reset Opties - - &Detach databases at shutdown - &Ontkoppel databases bij afsluiten - - - - MessagePage - - - Sign Message - Onderteken Bericht + + &Network + &Netwerk - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - U kunt berichten ondertekenen met een van uw adressen om te bewijzen dat u dit adres bezit. Pas op dat u geen onduidelijke dingen ondertekent, want phishingaanvallen zouden u voor de gek kunnen houden om zo uw identiteit te stelen. Onderteken alleen berichten waarmee u het volledig eens bent. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Open de CasinoCoin-poort automatisch op de router. Dit werkt alleen als de router UPnP ondersteunt en het aanstaat. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Het adres om het bericht mee te ondertekenen. (Vb.: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Kies adres uit adresboek - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Plak adres vanuit klembord - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Typ hier het bericht dat u wilt ondertekenen - - - - Copy the current signature to the system clipboard - Kopieer de huidige handtekening naar het systeemklembord - - - - &Copy Signature - &Kopiëer Handtekening - - - - Reset all sign message fields - Verwijder alles in de invulvelden - - - - Clear &All - Verwijder &Alles - - - - Click "Sign Message" to get signature - Klik "Onderteken Bericht" om de handtekening te verkrijgen - - - - Sign a message to prove you own this address - Onderteken een bericht om te bewijzen dat u dit adres bezit - - - - &Sign Message - O&nderteken Bericht - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Vul een Bitcoinadres in (bijv. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Fout bij het ondertekenen - - - - %1 is not a valid address. - %1 is geen geldig adres. - - - - %1 does not refer to a key. - %1 verwijst niet naar een sleutel. - - - - Private key for %1 is not available. - Geheime sleutel voor %1 is niet beschikbaar. - - - - Sign failed - Ondertekenen mislukt - - - - NetworkOptionsPage - - - Network - Netwerk - - - + Map port using &UPnP Portmapping via &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Open de Bitcoin-poort automatisch op de router. Dit werkt alleen als de router UPnP ondersteunt en het aanstaat. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Verbind met het CasinoCoin-netwerk via een SOCKS-proxy (bijv. wanneer u via Tor wilt verbinden) - - &Connect through SOCKS4 proxy: - &Verbind via SOCKS4 proxy: + + &Connect through SOCKS proxy: + &Verbind via een SOCKS-proxy - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Verbind met het Bitcoin-netwerk door een SOCKS4 proxy (bijv. wanneer Tor gebruikt wordt) - - - + Proxy &IP: Proxy &IP: - - &Port: - &Poort: - - - + IP address of the proxy (e.g. 127.0.0.1) IP-adres van de proxy (bijv. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Poort waarop de proxy luistert (bijv. 1234) + + &Port: + &Poort: - - - OptionsDialog - - Options - Opties + + Port of the proxy (e.g. 9050) + Poort van de proxy (bijv. 9050) + + + + SOCKS &Version: + SOCKS-&Versie: + + + + SOCKS version of the proxy (e.g. 5) + SOCKS-versie van de proxy (bijv. 5) + + + + &Window + &Scherm + + + + Show only a tray icon after minimizing the window. + Laat alleen een systeemvak-icoon zien wanneer het venster geminimaliseerd is + + + + &Minimize to the tray instead of the taskbar + &Minimaliseer naar het systeemvak in plaats van de taakbalk + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimaliseer het venster in de plaats van de applicatie af te sluiten als het venster gesloten wordt. Wanneer deze optie aan staan, kan de applicatie alleen worden afgesloten door Afsluiten te kiezen in het menu. + + + + M&inimize on close + Minimaliseer bij sluiten van het &venster + + + + &Display + &Interface + + + + User Interface &language: + Taal &Gebruikersinterface: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + De taal van de gebruikersinterface kan hier ingesteld worden. Deze instelling zal pas van kracht worden nadat CasinoCoin herstart wordt. + + + + &Unit to show amounts in: + &Eenheid om bedrag in te tonen: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Kies de standaard onderverdelingseenheid om weer te geven in uw programma, en voor het versturen van munten + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Of CasinoCoinadressen getoond worden in de transactielijst + + + + &Display addresses in transaction list + Toon a&dressen in de transactielijst + + + + &OK + &OK + + + + &Cancel + Ann&uleren + + + + &Apply + &Toepassen + + + + default + standaard + + + + Confirm options reset + Bevestig reset opties + + + + Some settings may require a client restart to take effect. + Sommige instellingen vereisen het herstarten van de client voordat ze in werking treden. + + + + Do you want to proceed? + Wilt u doorgaan? + + + + + Warning + Waarschuwing + + + + + This setting will take effect after restarting CasinoCoin. + Deze instelling zal pas van kracht worden na het herstarten van CasinoCoin. + + + + The supplied proxy address is invalid. + Het opgegeven proxyadres is ongeldig. OverviewPage - + Form Vorm - - - 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. - De weergegeven informatie kan verouderd zijn. Uw portemonnee synchroniseert automaticsh met het Bitcoinnetwerk nadat een verbinding is gelegd, maar dit proces is nog niet voltooid. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + De weergegeven informatie kan verouderd zijn. Uw portemonnee synchroniseert automaticsh met het CasinoCoinnetwerk nadat een verbinding is gelegd, maar dit proces is nog niet voltooid. - + Balance: Saldo: - - Number of transactions: - Aantal transacties: - - - + Unconfirmed: Onbevestigd: - + Wallet Portemonnee - + + Immature: + Immatuur: + + + + Mined balance that has not yet matured + Gedolven saldo dat nog niet tot wasdom is gekomen + + + <b>Recent transactions</b> <b>Recente transacties</b> - + Your current balance Uw huidige saldo - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Totaal van de transacties die nog moeten worden bevestigd en nog niet zijn meegeteld in uw huidige saldo - - Total number of transactions in wallet - Totaal aantal transacties in uw portemonnee - - - - + + out of sync niet gesynchroniseerd + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Kan casinocoin niet starten: click-to-pay handler + + QRCodeDialog - + QR Code Dialog QR-codescherm - - QR Code - QR-code - - - + Request Payment Vraag betaling aan - + Amount: Bedrag: - - BTC - BTC - - - + Label: Label: - + Message: Bericht: - + &Save As... &Opslaan Als... - + Error encoding URI into QR Code. Fout tijdens encoderen URI in QR-code - + + The entered amount is invalid, please check. + Het opgegeven bedrag is ongeldig, controleer het s.v.p. + + + Resulting URI too long, try to reduce the text for label / message. Resulterende URI te lang, probeer de tekst korter te maken voor het label/bericht. - + Save QR Code Sla QR-code op - + PNG Images (*.png) PNG-Afbeeldingen (*.png) @@ -1123,125 +1134,146 @@ Adres: %4 RPCConsole - - Bitcoin debug window - Bitcoin debugscherm - - - + Client name Clientnaam - - - - - - - - - + + + + + + + + + + N/A N.v.t. - + Client version Clientversie - + &Information &Informatie - - Client - Client + + Using OpenSSL version + Gebruikt OpenSSL versie - + Startup time Opstarttijd - + Network Netwerk - + Number of connections Aantal connecties - + On testnet Op testnet - + Block chain - Blokkenketen + Blokketen - + Current number of blocks Huidig aantal blokken - + Estimated total blocks Geschat totaal aantal blokken - + Last block time Tijd laatste blok - - Debug logfile - Debug-logbestand - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - Open het Bitcoin-debug-logbestand van de huidige datamap. Dit kan een paar seconden duren voor grote logbestanden. - - - + &Open &Open - + + Command-line options + Commandoregel-opties + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Toon het CasinoCoinQt-hulpbericht voor een lijst met mogelijke CasinoCoin commandoregel-opties. + + + + &Show + &Toon + + + &Console &Console - + Build date Bouwdatum - + + CasinoCoin - Debug window + CasinoCoin-debugscherm + + + + CasinoCoin Core + CasinoCoin Kern + + + + Debug log file + Debug-logbestand + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Open het CasinoCoindebug-logbestand van de huidige datamap. Dit kan een aantal seconden duren voor grote logbestanden. + + + Clear console Maak console leeg - - Welcome to the Bitcoin RPC console. - Welkom bij de Bitcoin RPC-console. + + Welcome to the CasinoCoin RPC console. + Welkom bij de CasinoCoin RPC-console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Gebruik de pijltjestoetsen om door de geschiedenis te navigeren, en <b>Ctrl-L</b> om het scherm leeg te maken. - + Type <b>help</b> for an overview of available commands. Typ <b>help</b> voor een overzicht van de beschikbare commando's. @@ -1249,109 +1281,109 @@ Adres: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Verstuur munten - + Send to multiple recipients at once Verstuur aan verschillende ontvangers ineens - - &Add Recipient + + Add &Recipient Voeg &Ontvanger Toe - + Remove all transaction fields Verwijder alle transactievelden - + Clear &All Verwijder &Alles - + Balance: Saldo: - + 123.456 BTC 123.456 BTC - + Confirm the send action Bevestig de verstuuractie - - &Send + + S&end &Verstuur - + <b>%1</b> to %2 (%3) <b>%1</b> aan %2 (%3) - + Confirm send coins Bevestig versturen munten - + Are you sure you want to send %1? Weet u zeker dat u %1 wil versturen? - + and en - - The recepient address is not valid, please recheck. - Het ontvangstadres is niet geldig, controleer uw opgave. + + The recipient address is not valid, please recheck. + Het ontvangstadres is niet geldig, controleer uw invoer. - + The amount to pay must be larger than 0. Het ingevoerde bedrag moet groter zijn dan 0. - + The amount exceeds your balance. Bedrag is hoger dan uw huidige saldo - + The total exceeds your balance when the %1 transaction fee is included. Totaal overschrijdt uw huidige saldo wanneer de %1 transactiekosten worden meegerekend - + Duplicate address found, can only send to each address once per send operation. Dubbel adres gevonden, u kunt slechts eenmaal naar een bepaald adres verzenden per verstuurtransactie - - Error: Transaction creation failed. - Fout: Aanmaak transactie mislukt + + Error: Transaction creation failed! + Fout: Aanmaak transactie mislukt! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. Fout: De transactie was afgewezen. Dit kan gebeuren als u eerder uitgegeven munten opnieuw wilt versturen, zoals wanneer u een kopie van uw portemonneebestand (wallet.dat) heeft gebruikt en in de kopie deze munten zijn uitgegeven, maar in de huidige portemonnee deze nog niet als zodanig zijn gemarkeerd. @@ -1359,217 +1391,456 @@ Adres: %4 SendCoinsEntry - + Form Vorm - + A&mount: Bedra&g: - + Pay &To: Betaal &Aan: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Het adres waaraan u wilt betalen (bijv. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Vul een label in voor dit adres om het toe te voegen aan uw adresboek - + &Label: &Label: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Het adres waaraan u wilt betalen (bijv. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Kies adres uit adresboek - + Alt+A Alt+A - + Paste address from clipboard Plak adres vanuit klembord - + Alt+P Alt+P - + Remove this recipient Verwijder deze ontvanger - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Vul een Bitcoinadres in (bijv. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Vul een CasinoCoinadres in (bijv. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Handtekeningen - Onderteken een bericht / Verifiëer een handtekening + + + + &Sign Message + O&nderteken Bericht + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + U kunt berichten ondertekenen met een van uw adressen om te bewijzen dat u dit adres bezit. Pas op dat u geen onduidelijke dingen ondertekent, want phishingaanvallen zouden u kunnen misleiden om zo uw identiteit te stelen. Onderteken alleen berichten waarmee u het volledig eens bent. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Het adres om het bericht mee te ondertekenen (Vb.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2). + + + + + Choose an address from the address book + Kies een adres uit het adresboek + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Plak adres vanuit klembord + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Typ hier het bericht dat u wilt ondertekenen + + + + Signature + Handtekening + + + + Copy the current signature to the system clipboard + Kopieer de huidige handtekening naar het systeemklembord + + + + Sign the message to prove you own this CasinoCoin address + Onderteken een bericht om te bewijzen dat u een bepaald CasinoCoinadres bezit + + + + Sign &Message + Onderteken &Bericht + + + + Reset all sign message fields + Verwijder alles in de invulvelden + + + + + Clear &All + Verwijder &Alles + + + + &Verify Message + &Verifiëer Bericht + + + + Enter the signing 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. + Voer het ondertekenende adres, bericht en handtekening hieronder in (let erop dat u nieuwe regels, spaties en tabs juist overneemt) om de handtekening te verifiëren. Let erop dat u niet meer uit het bericht interpreteert dan er daadwerkelijk staat, om te voorkomen dat u wordt misleid in een man-in-the-middle-aanval. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Het adres waarmee bet bericht was ondertekend (Vb.: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2). + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Controleer een bericht om te verifiëren dat het gespecificeerde CasinoCoinadres het bericht heeft ondertekend. + + + + Verify &Message + Verifiëer &Bericht + + + + Reset all verify message fields + Verwijder alles in de invulvelden + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Vul een CasinoCoinadres in (bijv. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Klik "Onderteken Bericht" om de handtekening te genereren + + + + Enter CasinoCoin signature + Voer CasinoCoin-handtekening in + + + + + The entered address is invalid. + Het opgegeven adres is ongeldig. + + + + + + + Please check the address and try again. + Controleer s.v.p. het adres en probeer het opnieuw. + + + + + The entered address does not refer to a key. + Het opgegeven adres verwijst niet naar een sleutel. + + + + Wallet unlock was cancelled. + Portemonnee-ontsleuteling is geannuleerd + + + + Private key for the entered address is not available. + Geheime sleutel voor het ingevoerde adres is niet beschikbaar. + + + + Message signing failed. + Ondertekenen van het bericht is mislukt. + + + + Message signed. + Bericht ondertekend. + + + + The signature could not be decoded. + De handtekening kon niet worden gedecodeerd. + + + + + Please check the signature and try again. + Controleer s.v.p. de handtekening en probeer het opnieuw. + + + + The signature did not match the message digest. + De handtekening hoort niet bij het bericht. + + + + Message verification failed. + Berichtverificatie mislukt. + + + + Message verified. + Bericht correct geverifiëerd. + + + + SplashScreen + + + The CasinoCoin developers + De CasinoCoin-ontwikkelaars + + + + [testnet] + [testnetwerk] TransactionDesc - - Open for %1 blocks - Openen voor %1 blokken - - - + Open until %1 Openen totdat %1 - - %1/offline? - %1/niet verbonden? + + %1/offline + %1/offline - + %1/unconfirmed %1/onbevestigd - + %1 confirmations %1 bevestigingen - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , uitgezonden naar %n node, uitgezonden naar %n nodes - - , has not been successfully broadcast yet - , is nog niet succesvol uitgezonden + + Date + Datum - - , broadcast through %1 node - , uitgezonden naar %1 node + + Source + Bron - - , broadcast through %1 nodes - , uitgezonden naar %1 nodes + + Generated + Gegenereerd - - <b>Date:</b> - <b>Datum:</b> + + + From + Van - - <b>Source:</b> Generated<br> - <b>Bron:</b>Gegenereerd<br> + + + + To + Aan - - - <b>From:</b> - <b>Van:</b> + + + own address + eigen adres - - unknown - onbekend + + label + label - - - - <b>To:</b> - <b> Aan:</b> + + + + + + Credit + Credit + + + + matures in %n more block(s) + komt tot wasdom na %n nieuw blokkomt tot wasdom na %n nieuwe blokken - - (yours, label: - (Uw adres, label: + + not accepted + niet geaccepteerd - - (yours) - (uw) + + + + + Debit + Debet - - - - - <b>Credit:</b> - <b>Bij:</b> + + Transaction fee + Transactiekosten - - (%1 matures in %2 more blocks) - (%1 komt beschikbaar na %2 blokken) + + Net amount + Netto bedrag - - (not accepted) - (niet geaccepteerd) + + Message + Bericht - - - - <b>Debit:</b> - <b>Af:</b> + + Comment + Opmerking - - <b>Transaction fee:</b> - <b>Transactiekosten:</b> - - - - <b>Net amount:</b> - <b>Netto bedrag:</b> - - - - Message: - Bericht: - - - - Comment: - Opmerking: - - - - Transaction ID: + + Transaction ID Transactie-ID: - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Gegeneerde munten moeten 120 blokken wachten voor ze kunnen worden uitgegeven. Uw net gegenereerde blok is uitgezonden aan het netwerk om te worden toegevoegd aan de blokkenketen. Als het niet wordt geaccepteerd in de keten, zal het blok als "ongeldig" worden aangemerkt en kan het niet worden uitgegeven. Dit kan soms gebeuren als een andere node net iets sneller een blok heeft gegenereerd; een paar seconden voor het uwe. + + Generated coins must mature 120 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. + Gegeneerde munten moeten 120 blokken wachten voordat ze tot wasdom komen en kunnen worden uitgegeven. Uw net gegenereerde blok is uitgezonden aan het netwerk om te worden toegevoegd aan de blokketen. Als het niet wordt geaccepteerd in de keten, zal het blok als "niet geaccepteerd" worden aangemerkt en kan het niet worden uitgegeven. Dit kan soms gebeuren als een andere node net iets sneller een blok heeft gegenereerd; een paar seconden voor het uwe. + + + + Debug information + Debug-informatie + + + + Transaction + Transactie + + + + Inputs + Inputs + + + + Amount + Bedrag + + + + true + waar + + + + false + onwaar + + + + , has not been successfully broadcast yet + , is nog niet met succes uitgezonden + + + + Open for %n more block(s) + Open voor nog %n blokOpen voor nog %n blokken + + + + unknown + onbekend TransactionDescDialog - + Transaction details Transactiedetails - + This pane shows a detailed description of the transaction Dit venster laat een uitgebreide beschrijving van de transactie zien @@ -1577,117 +1848,117 @@ Adres: %4 TransactionTableModel - + Date Datum - + Type Type - + Address Adres - + Amount Bedrag - - Open for %n block(s) - Open gedurende %n blokOpen gedurende %n blokken + + Open for %n more block(s) + Open voor nog %n blokOpen voor nog %n blokken - + Open until %1 Open tot %1 - + Offline (%1 confirmations) Niet verbonden (%1 bevestigingen) - + Unconfirmed (%1 of %2 confirmations) Onbevestigd (%1 van %2 bevestigd) - + Confirmed (%1 confirmations) Bevestigd (%1 bevestigingen) - - Mined balance will be available in %n more blocks - Ontgonnen saldo komt beschikbaar na %n blokOntgonnen saldo komt beschikbaar na %n blokken + + Mined balance will be available when it matures in %n more block(s) + Gedolven saldo zal beschikbaar komen als het tot wasdom komt na %n blokGedolven saldo zal beschikbaar komen als het tot wasdom komt na %n blokken - + This block was not received by any other nodes and will probably not be accepted! Dit blok is niet ontvangen bij andere nodes en zal waarschijnlijk niet worden geaccepteerd! - + Generated but not accepted Gegenereerd maar niet geaccepteerd - + Received with Ontvangen met - + Received from Ontvangen van - + Sent to Verzonden aan - + Payment to yourself Betaling aan uzelf - + Mined - Ontgonnen + Gedolven - + (n/a) (nvt) - + Transaction status. Hover over this field to show number of confirmations. Transactiestatus. Houd de muiscursor boven dit veld om het aantal bevestigingen te laten zien. - + Date and time that the transaction was received. Datum en tijd waarop deze transactie is ontvangen. - + Type of transaction. Type transactie. - + Destination address of transaction. - Ontvangend adres van transactie + Ontvangend adres van transactie. - + Amount removed from or added to balance. Bedrag verwijderd van of toegevoegd aan saldo @@ -1695,852 +1966,973 @@ Adres: %4 TransactionView - - + + All Alles - + Today Vandaag - + This week Deze week - + This month Deze maand - + Last month Vorige maand - + This year Dit jaar - + Range... Bereik... - + Received with Ontvangen met - + Sent to Verzonden aan - + To yourself Aan uzelf - + Mined - Ontgonnen + Gedolven - + Other Anders - + Enter address or label to search Vul adres of label in om te zoeken - + Min amount Min. bedrag - + Copy address Kopieer adres - + Copy label Kopieer label - + Copy amount Kopieer bedrag - + + Copy transaction ID + Kopieer transactie-ID + + + Edit label Bewerk label - + Show transaction details Toon transactiedetails - + Export Transaction Data Exporteer transactiegegevens - + Comma separated file (*.csv) Kommagescheiden bestand (*.csv) - + Confirmed Bevestigd - + Date Datum - + Type Type - + Label Label - + Address Adres - + Amount Bedrag - + ID ID - + Error exporting Fout bij exporteren - + Could not write to file %1. Kon niet schrijven naar bestand %1. - + Range: Bereik: - + to naar - - VerifyMessageDialog - - - Verify Signed Message - Verifieer Ondertekend Bericht - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - Voer het bericht en de handtekening hieronder in (let erop dat enters, spaties, tabs en andere onzichtbare karakters goed worden overgenomen) om het Bitcoin-adres te verkrijgen dat gebruikt is om het bericht te ondertekenen. - - - - Verify a message and obtain the Bitcoin address used to sign the message - Verifiëer een bericht en verkrijg het Bitcoinadres dat gebruikt is om het bericht te ondertekenen - - - - &Verify Message - &Verifiëer Bericht - - - - Copy the currently selected address to the system clipboard - Kopieer het huidig geselecteerde adres naar het klembord - - - - &Copy Address - &Kopiëer Adres - - - - Reset all verify message fields - Verwijder alles in de invulvelden - - - - Clear &All - Verwijder &Alles - - - - Enter Bitcoin signature - Voer Bitcoin-handtekening in - - - - Click "Verify Message" to obtain address - Klik "Verifiëer Bericht" om het adres te verkrijgen - - - - - Invalid Signature - Ongeldige Handtekening - - - - The signature could not be decoded. Please check the signature and try again. - De handtekening kon niet gedecodeerd worden. Controleer svp de handtekening en probeer het opnieuw. - - - - The signature did not match the message digest. Please check the signature and try again. - De handtekening correspondeerde niet met het bericht. Controleer svp de handtekening en probeer het opnieuw. - - - - Address not found in address book. - Adres niet gevonden in adresboek. - - - - Address found in address book: %1 - Adres gevonden in adresboek: %1 - - WalletModel - - Sending... - Versturen... + + Send Coins + Verstuur munten - WindowOptionsPage + WalletView - - Window - Venster + + &Export + &Exporteer - - &Minimize to the tray instead of the taskbar - &Minimaliseer naar het systeemvak in plaats van de taakbalk + + Export the data in the current tab to a file + Exporteer de data in de huidige tab naar een bestand - - Show only a tray icon after minimizing the window - Laat alleen een systeemvak-icoon zien wanneer het venster geminimaliseerd is + + Backup Wallet + Portomonnee backuppen - - M&inimize on close - Minimaliseer bij &sluiten van het venster + + Wallet Data (*.dat) + Portemonnee-data (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimaliseer het venster in de plaats van de applicatie af te sluiten als het venster gesloten wordt. Wanneer deze optie aan staan, kan de applicatie alleen worden afgesloten door Afsluiten te kiezen in het menu. + + Backup Failed + Backup Mislukt + + + + There was an error trying to save the wallet data to the new location. + Er is een fout opgetreden bij het wegschrijven van de portemonnee-data naar de nieuwe locatie. + + + + Backup Successful + Backup Succesvol + + + + The wallet data was successfully saved to the new location. + De portemonneedata is succesvol opgeslagen op de nieuwe locatie. bitcoin-core - - Bitcoin version - Bitcoinversie + + CasinoCoin version + CasinoCoinversie - + Usage: Gebruik: - - Send command to -server or bitcoind - Stuur commando naar -server of bitcoind - + + Send command to -server or casinocoind + Stuur commando naar -server of casinocoind - + List commands - List van commando's - + Lijst van commando's - + Get help for a command - Toon hulp voor een commando - + Toon hulp voor een commando - + Options: - Opties: + Opties: + + + + Specify configuration file (default: casinocoin.conf) + Specificeer configuratiebestand (standaard: casinocoin.conf) - - Specify configuration file (default: bitcoin.conf) - Specifieer configuratiebestand (standaard: bitcoin.conf) + + Specify pid file (default: casinocoind.pid) + Specificeer pid-bestand (standaard: casinocoind.pid) - - Specify pid file (default: bitcoind.pid) - Specifieer pid-bestand (standaard: bitcoind.pid) - - - - - Generate coins - Genereer munten - - - - - Don't generate coins - Genereer geen munten - - - - + Specify data directory - Stel datamap in - + Stel datamap in - + Set database cache size in megabytes (default: 25) Stel databankcachegrootte in in megabytes (standaard: 25) - - Set database disk log size in megabytes (default: 100) - Stel databankloggrootte in in megabytes (standaard: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Luister voor verbindingen op <poort> (standaard: 47950 of testnet: 17950) - - Specify connection timeout (in milliseconds) - Specificeer de time-out tijd (in milliseconden) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Luister voor verbindingen op <poort> (standaard: 8333 of testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Onderhoud maximaal <n> verbindingen naar peers (standaard: 125) - - Connect only to the specified node - Verbind alleen met deze node - - - - + Connect to a node to retrieve peer addresses, and disconnect Verbind naar een node om adressen van anderen op te halen, en verbreek vervolgens de verbinding - + Specify your own public address Specificeer uw eigen publieke adres - - Only connect to nodes in network <net> (IPv4 or IPv6) - Verbind slechts naar nodes in netwerk <net> (IPv4 of IPv6) - - - - Try to discover public IP address (default: 1) - Probeer om publieke IP-adres te achterhalen (standaard: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - Bind aan gegeven adres. Gebruik [host]:poort -notatie voor IPv6 - - - + Threshold for disconnecting misbehaving peers (default: 100) Drempel om verbinding te verbreken naar zich misdragende peers (standaard: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Aantal seconden dat zich misdragende peers niet opnieuw mogen verbinden (standaard: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maximale ontvangstbuffer per connectie, <n>*1000 bytes (standaard: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Er is een fout opgetreden tijdens het instellen van de inkomende RPC-poort %u op IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maximale zendbuffer per connectie, <n>*1000 bytes (standaard: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Wacht op JSON-RPC-connecties op poort <port> (standaard: 47970 of testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - Ontkoppel blok- en adresdatabases. Verhoogt afsluittijd (standaard: 0) - - - + Accept command line and JSON-RPC commands - Aanvaard commandoregel en JSON-RPC commando's - + Aanvaard commandoregel- en JSON-RPC-commando's - + Run in the background as a daemon and accept commands - Draai in de achtergrond als daemon en aanvaard commando's - + Draai in de achtergrond als daemon en aanvaard commando's - + Use the test network - Gebruik het testnetwerk - + Gebruik het testnetwerk - - Output extra debugging information - Toon extra debuggingsinformatie + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accepteer verbindingen van buitenaf (standaard: 1 als geen -proxy of -connect is opgegeven) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, u moet een RPC-wachtwoord instellen in het configuratiebestand: %s +U wordt aangeraden het volgende willekeurige wachtwoord te gebruiken: +rpcuser=casinocoinrpc +rpcpassword=%s +(u hoeft dit wachtwoord niet te onthouden) +De gebruikersnaam en wachtwoord mogen niet hetzelfde zijn. +Als het bestand niet bestaat, make hem dan aan met leesrechten voor enkel de eigenaar. +Het is ook aan te bevelen "alertnotify" in te stellen zodat u op de hoogte gesteld wordt van problemen; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Er is een fout opgetreden tijdens het instellen van de inkomende RPC-poort %u op IPv6, terugval naar IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Bind aan opgegeven adres en luister er altijd op. Gebruik [host]:port notatie voor IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Kan geen lock op de datamap %s verkrijgen. CasinoCoin draait vermoedelijk reeds. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Fout: De transactie was afgewezen! Dit kan gebeuren als sommige munten in uw portemonnee al eerder uitgegeven zijn, zoals wanneer u een kopie van uw wallet.dat heeft gebruikt en in de kopie deze munten zijn uitgegeven, maar in deze portemonnee die munten nog niet als zodanig zijn gemarkeerd. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Fout: Deze transactie vereist transactiekosten van tenminste %s, vanwege zijn grootte, complexiteit, of het gebruik van onlangs ontvangen munten! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Voer opdracht uit zodra een relevante melding ontvangen is (%s wordt in cmd vervangen door het bericht) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Voer opdracht uit zodra een portemonneetransactie verandert (%s in cmd wordt vervangen door TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Stel maximumgrootte in in bytes voor hoge-prioriteits-/lage-transactiekosten-transacties (standaard: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Dit is een pre-release testversie - gebruik op eigen risico! Gebruik deze niet voor het delven van munten of handelsdoeleinden + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Waarschuwing: -paytxfee is zeer hoog ingesteld. Dit zijn de transactiekosten die u betaalt bij het versturen van een transactie. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Waarschuwing: Weergegeven transacties zijn mogelijk niet correct! Mogelijk dient u te upgraden, of andere nodes dienen te upgraden. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Waarschuwing: Controleer dat de datum en tijd op uw computer correct zijn ingesteld. Als uw klok fout staat zal CasinoCoin niet correct werken. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Waarschuwing: Fout bij het lezen van wallet.dat! Alle sleutels zijn in goede orde uitgelezen, maar transactiedata of adresboeklemma's zouden kunnen ontbreken of fouten bevatten. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Waarschuwing: wallet.dat is corrupt, data is veiliggesteld! Originele wallet.dat is opgeslagen als wallet.{tijdstip}.bak in %s; als uw balans of transacties incorrect zijn dient u een backup terug te zetten. + + + + Attempt to recover private keys from a corrupt wallet.dat + Poog de geheime sleutels uit een corrupt wallet.dat bestand terug te halen + + + + Block creation options: + Blokcreatie-opties: + + + + Connect only to the specified node(s) + Verbind alleen naar de gespecificeerde node(s) + + + + Corrupted block database detected + Corrupte blokkendatabase gedetecteerd + + + + Discover own IP address (default: 1 when listening and no -externalip) + Ontdek eigen IP-adres (standaard: 1 als er wordt geluisterd en geen -externalip is opgegeven) + + + + Do you want to rebuild the block database now? + Wilt u de blokkendatabase nu herbouwen? + + + + Error initializing block database + Fout bij intialisatie blokkendatabase + + + + Error initializing wallet database environment %s! + Probleem met initializeren van de database-omgeving %s! + + + + Error loading block database + Fout bij het laden van blokkendatabase + + + + Error opening block database + Fout bij openen blokkendatabase + + + + Error: Disk space is low! + Fout: Weinig vrije diskruimte! + + + + Error: Wallet locked, unable to create transaction! + Fout: Portemonnee vergrendeld, aanmaak transactie niet mogelijk! + + + + Error: system error: + Fout: Systeemfout: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Mislukt om op welke poort dan ook te luisteren. Gebruik -listen=0 as u dit wilt. + + + + Failed to read block info + Lezen van blokinformatie mislukt + + + + Failed to read block + Lezen van blok mislukt + + + + Failed to sync block index + Synchroniseren van blokindex mislukt + + + + Failed to write block index + Schrijven van blokindex mislukt + + + + Failed to write block info + Schrijven van blokinformatie mislukt + + + + Failed to write block + Schrijven van blok mislukt + + + + Failed to write file info + Schrijven van bestandsinformatie mislukt + + + + Failed to write to coin database + Schrijven naar coindatabase mislukt + + + + Failed to write transaction index + Schrijven van transactieindex mislukt + + + + Failed to write undo data + Schrijven van undo-data mislukt + + + + Find peers using DNS lookup (default: 1 unless -connect) + Vind andere nodes d.m.v. DNS-naslag (standaard: 1 tenzij -connect) + + + + Generate coins (default: 0) + Genereer munten (standaard: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Aantal te checken blokken bij het opstarten (standaard: 288, 0 = allemaal) + + + + How thorough the block verification is (0-4, default: 3) + Hoe grondig de blokverificatie is (0-4, standaard: 3) + + + + Not enough file descriptors available. + Niet genoeg file descriptors beschikbaar. + + + + Rebuild block chain index from current blk000??.dat files + Blokketen opnieuw opbouwen van huidige blk000??.dat-bestanden + + + + Set the number of threads to service RPC calls (default: 4) + Stel het aantal threads in om RPC-aanvragen mee te bedienen (standaard: 4) + + + + Verifying blocks... + Blokken aan het controleren... + + + + Verifying wallet... + Portomonnee aan het controleren... + + + + Imports blocks from external blk000??.dat file + Importeert blokken van extern blk000??.dat bestand + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Stel het aantal threads voor scriptverificatie in (max 16, 0 = auto, <0 = laat zoveel cores vrij, standaard: 0) + + + + Information + Informatie + + + + Invalid -tor address: '%s' + Ongeldig -tor adres: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ongeldig bedrag voor -minrelaytxfee=<bedrag>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ongeldig bedrag voor -mintxfee=<bedrag>: '%s' + + + + Maintain a full transaction index (default: 0) + Onderhoud een volledige transactieindex (standaard: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maximum per-connectie ontvangstbuffer, <n>*1000 bytes (standaard: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maximum per-connectie zendbuffer, <n>*1000 bytes (standaard: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Accepteer alleen blokketen die overeenkomt met de ingebouwde checkpoints (standaard: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Verbind alleen naar nodes in netwerk <net> (IPv4, IPv6 of Tor) + + + + Output extra debugging information. Implies all other -debug* options + Output extra debugginginformatie. Impliceert alle andere -debug* opties + + + + Output extra network debugging information + Output extra netwerk-debugginginformatie + + + Prepend debug output with timestamp Voorzie de debuggingsuitvoer van een tijdsaanduiding - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL-opties: (zie de CasinoCoin wiki voor SSL-instructies) + + + + Select the version of socks proxy to use (4-5, default: 5) + Selecteer de versie van de SOCKS-proxy om te gebruiken (4 of 5, standaard is 5) + + + Send trace/debug info to console instead of debug.log file Stuur trace/debug-info naar de console in plaats van het debug.log bestand - + Send trace/debug info to debugger Stuur trace/debug-info naar debugger - + + Set maximum block size in bytes (default: 250000) + Stel maximum blokgrootte in in bytes (standaard: 250000) + + + + Set minimum block size in bytes (default: 0) + Stel minimum blokgrootte in in bytes (standaard: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Verklein debug.log-bestand bij het opstarten van de client (standaard: 1 als geen -debug) + + + + Signing transaction failed + Ondertekenen van transactie mislukt + + + + Specify connection timeout in milliseconds (default: 5000) + Specificeer de time-outtijd in milliseconden (standaard: 5000) + + + + System error: + Systeemfout: + + + + Transaction amount too small + Transactiebedrag te klein + + + + Transaction amounts must be positive + Transactiebedragen moeten positief zijn + + + + Transaction too large + Transactie te groot + + + + Use UPnP to map the listening port (default: 0) + Gebruik UPnP om de luisterende poort te mappen (standaard: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Gebruik UPnP om de luisterende poort te mappen (standaard: 1 als er wordt geluisterd) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Gebruik proxy om 'tor hidden services' te bereiken (standaard: hetzelfde als -proxy) + + + Username for JSON-RPC connections - Gebruikersnaam voor JSON-RPC verbindingen - + Gebruikersnaam voor JSON-RPC-verbindingen - + + Warning + Waarschuwing + + + + Warning: This version is obsolete, upgrade required! + Waarschuwing: Deze versie is verouderd, een upgrade is vereist! + + + + You need to rebuild the databases using -reindex to change -txindex + U moet de databases herbouwen met behulp van -reindex om -txindex te kunnen veranderen + + + + wallet.dat corrupt, salvage failed + wallet.dat corrupt, veiligstellen mislukt + + + Password for JSON-RPC connections - Wachtwoord voor JSON-RPC verbindingen - + Wachtwoord voor JSON-RPC-verbindingen - - Listen for JSON-RPC connections on <port> (default: 8332) - Luister voor JSON-RPC verbindingen op <poort> (standaard: 8332) - - - - + Allow JSON-RPC connections from specified IP address - Sta JSON-RPC verbindingen van opgegeven IP adres toe - + Sta JSON-RPC verbindingen van opgegeven IP-adres toe - + Send commands to node running on <ip> (default: 127.0.0.1) - Verstuur commando's naar proces dat op <ip> draait (standaard: 127.0.0.1) - + Verstuur commando's naar proces dat op <ip> draait (standaard: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Voer commando uit zodra het beste blok verandert (%s in cmd wordt vervangen door blockhash) - + Upgrade wallet to latest format Vernieuw portemonnee naar nieuwste versie - + Set key pool size to <n> (default: 100) - Stel sleutelpoelgrootte in op <n> (standaard: 100) - + Stel sleutelpoelgrootte in op <n> (standaard: 100) - + Rescan the block chain for missing wallet transactions - Doorzoek de blokkenketen op ontbrekende portemonnee-transacties + Doorzoek de blokketen op ontbrekende portemonnee-transacties - - How many blocks to check at startup (default: 2500, 0 = all) - Het aantal blokken na te kijken bij opstarten (standaard: 2500, 0=alle) - - - - How thorough the block verification is (0-6, default: 1) - De grondigheid van de blokverificatie (0-6, standaard: 1) - - - - Imports blocks from external blk000?.dat file - Importeert blokken van extern blk000?.dat bestand - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL-opties: (zie de Bitcoin wiki voor SSL-instructies) - - - + Use OpenSSL (https) for JSON-RPC connections - Gebruik OpenSSL (https) voor JSON-RPC verbindingen - + Gebruik OpenSSL (https) voor JSON-RPC-verbindingen - + Server certificate file (default: server.cert) - Certificaat-bestand voor server (standaard: server.cert) - + Certificaat-bestand voor server (standaard: server.cert) - + Server private key (default: server.pem) - Geheime sleutel voor server (standaard: server.pem) - + Geheime sleutel voor server (standaard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Aanvaardbare ciphers (standaard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - Waarschuwing: Weinig schijfruimte vrij - - - + This help message - Dit helpbericht - + Dit helpbericht - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Kan geen lock op de datamap %s verkrijgen. Bitcoin draait vermoedelijk reeds. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) Niet in staat om aan %s te binden op deze computer (bind gaf error %d, %s) - + Connect through socks proxy Verbind via een socks-proxy - - Select the version of socks proxy to use (4 or 5, 5 is default) - Selecteer de versie van de socks proxy om te gebruiken (4 of 5, 5 is standaard) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - Gebruik geen proxy voor verbindingen naar netwerk <net> (IPv4 of IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect Sta DNS-naslag toe voor -addnode, -seednode en -connect - - Pass DNS requests to (SOCKS5) proxy - Stuur DNS-verzoeken via (SOCKS5)proxy - - - + Loading addresses... Adressen aan het laden... - - Error loading blkindex.dat - Fout bij laden blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Fout bij laden wallet.dat: Portemonnee corrupt - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Fout bij laden wallet.dat: Portemonnee vereist een nieuwere versie van Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Fout bij laden wallet.dat: Portemonnee vereist een nieuwere versie van CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Portemonnee moest herschreven worden: Herstart Bitcoin om te voltooien + + Wallet needed to be rewritten: restart CasinoCoin to complete + Portemonnee moest herschreven worden: Herstart CasinoCoin om te voltooien - + Error loading wallet.dat Fout bij laden wallet.dat - + Invalid -proxy address: '%s' Ongeldig -proxy adres: '%s' - - Unknown network specified in -noproxy: '%s' - Onbekend netwerk gespecificeerd in -noproxy: '%s' - - - + Unknown network specified in -onlynet: '%s' Onbekend netwerk gespecificeerd in -onlynet: '%s' - + Unknown -socks proxy version requested: %i Onbekende -socks proxyversie aangegeven: %i - + Cannot resolve -bind address: '%s' Kan -bind adres niet herleiden: '%s' - - Not listening on any port - Op geen enkele poort aan het luisteren - - - + Cannot resolve -externalip address: '%s' Kan -externlip adres niet herleiden: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ongeldig bedrag voor -paytxfee=<bedrag>: '%s' - - Error: could not start node - Fout: Kon node niet starten - - - - Error: Wallet locked, unable to create transaction - Fout: Portemonnee gesloten, transactie maken niet mogelijk - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Fout: Deze transactie heeft transactiekosten nodig van tenminste %s, vanwege zijn grootte, ingewikkeldheid, of het gebruik van onlangs ontvangen munten - - - - Error: Transaction creation failed - Fout: Aanmaak transactie mislukt - - - - Sending... - Aan het versturen... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Fout: De transactie was afgewezen. Dit kan gebeuren als u eerder uitgegeven munten opnieuw wilt versturen, zoals wanneer u een kopie van uw wallet.dat heeft gebruikt en in de kopie deze munten zijn gemarkeerd als uitgegeven, maar in de huidige nog niet. - - - + Invalid amount - Ongeldig aantal + Ongeldig bedrag - + Insufficient funds Ontoereikend saldo - + Loading block index... Blokindex aan het laden... - + Add a node to connect to and attempt to keep the connection open - Voeg een knooppunt om te verbinden toe en probeer de verbinding open te houden + Voeg een node om naar te verbinden toe en probeer de verbinding open te houden - - Unable to bind to %s on this computer. Bitcoin is probably already running. - Niet in staat om aan %s te binden op deze computer. Bitcoin draait vermoedelijk reeds. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Niet in staat om aan %s te binden op deze computer. CasinoCoin draait vermoedelijk reeds. - - Find peers using internet relay chat (default: 0) - Vind anderen door middel van Internet Relay Chat (standaard: 0) - - - - Accept connections from outside (default: 1) - Accepteer verbindingen van buitenaf (standaard: 1) - - - - Find peers using DNS lookup (default: 1) - Vind anderen door middel van een DNS-naslag (standaard: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Gebruik Universal Plug and Play om de inkomende poort te mappen (standaard: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Gebruik Universal Plug and Play om de inkomende poort te mappen (standaard: 0) - - - + Fee per KB to add to transactions you send Kosten per KB om aan transacties toe te voegen die u verstuurt - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - Waarschuwing: -paytxfee is zeer hoog ingesteld. Dit zijn de transactiekosten die u betaalt bij het versturen van een transactie. - - - + Loading wallet... Portemonnee aan het laden... - + Cannot downgrade wallet Kan portemonnee niet downgraden - - Cannot initialize keypool - Kan sleutel-pool niet initialiseren - - - + Cannot write default address - Kan standaard adres niet schrijven + Kan standaardadres niet schrijven - + Rescanning... - Opnieuw aan het scannen ... + Blokketen aan het doorzoeken... - + Done loading Klaar met laden - + To use the %s option Om de %s optie te gebruiken - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, je moet een rpcpassword instellen in het configuratie bestand: - %s -Het is aangeraden het volgende willekeurig wachtwoord te gebruiken: -rpccuser=bitcoinrpc -rpcpassword=%s -(het is niet nodig om het wachtwoord te onthouden) -Als het bestand niet bestaat, maak het aan, met een alleen-lezen permissie. - - - - + Error Fout - - An error occured while setting up the RPC port %i for listening: %s - Er is een fout opgetreden tijdens het opzetten van de inkomende RPC-poort %i: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - Je moet rpcpassword=<password> instellen in het configuratie bestand: + U dient rpcpassword=<wachtwoord> in te stellen in het configuratiebestand: %s -Als het bestand niet bestaat, maak het dan aan, met een alleen-lezen permissie. - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Waarschuwing: Controleer dat de datum en tijd op uw computer correct zijn ingesteld. Als uw klok fout staat zal Bitcoin niet correct werken. +Als het bestand niet bestaat, maak het dan aan, met een alleen-lezen-permissie. \ No newline at end of file diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index fe44a97..694ea71 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -3,127 +3,160 @@ AboutDialog - - About Bitcoin - O Bitcoin + + About CasinoCoin + O CasinoCoin - - <b>Bitcoin</b> version - Wersja <b>Bitcoin</b> + + <b>CasinoCoin</b> version + Wersja <b>CasinoCoin</b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin Developers - + Oprogramowanie eksperymentalne. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - - - -Pomóż w tłumaczeniu: -www.transifex.net/projects/p/bitcoin/ +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + Copyright + Prawo autorskie + + + + The CasinoCoin developers + Deweloperzy CasinoCoin AddressBookPage - + Address Book Książka Adresowa - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Tutaj znajdują się twoje adresy Bitcoin do odbioru płatności. Możesz nadać oddzielne adresy dla każdego z wysyłających monety, żeby śledzić oddzielnie ich opłaty. - - - + Double-click to edit address or label Kliknij dwukrotnie, aby edytować adres lub etykietę - + Create a new address Utwórz nowy adres - + Copy the currently selected address to the system clipboard Skopiuj aktualnie wybrany adres do schowka - + &New Address &Nowy Adres - - &Copy Address - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Tutaj znajdują się twoje adresy CasinoCoin do odbioru płatności. Możesz nadać oddzielne adresy dla każdego z wysyłających monety, żeby śledzić oddzielnie ich opłaty. - + + &Copy Address + &Kopiuj adres + + + Show &QR Code Pokaż Kod &QR - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address Podpisz wiadomość aby dowieść, że ten adres jest twój - - &Sign Message - Podpi&sz Wiadomość + + Sign &Message + Podpisz wiado&mość - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Usuń aktualnie wybrany adres z listy. Tylko adresy nadawcze mogą być usunięte. + + Delete the currently selected address from the list + Usuń zaznaczony adres z listy - + + Export the data in the current tab to a file + Eksportuj dane z aktywnej karty do pliku + + + + &Export + &Eksportuj + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Zweryfikuj wiadomość, aby upewnić się, że została podpisana odpowiednim adresem CasinoCoin. + + + + &Verify Message + &Zweryfikuj wiadomość + + + &Delete &Usuń - - Copy &Label - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Tutaj znajdują się Twoje adresy CasinoCoin do wysyłania płatności. Zawsze sprawdzaj ilość i adres odbiorcy przed wysyłką monet. - + + Copy &Label + Kopiuj &Etykietę + + + &Edit &Edytuj - + + Send &Coins + Wyślij monety + + + Export Address Book Data Eksportuj książkę adresową - + Comma separated file (*.csv) Plik *.CSV (rozdzielany przecinkami) - + Error exporting Błąd podczas eksportowania - + Could not write to file %1. Błąd zapisu do pliku %1. @@ -131,17 +164,17 @@ www.transifex.net/projects/p/bitcoin/ AddressTableModel - + Label Etykieta - + Address Adres - + (no label) (bez etykiety) @@ -149,432 +182,460 @@ www.transifex.net/projects/p/bitcoin/ AskPassphraseDialog - + Passphrase Dialog - + Okienko Hasła - + Enter passphrase Wpisz hasło - + New passphrase Nowe hasło - + Repeat new passphrase Powtórz nowe hasło - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Wprowadź nowe hasło dla portfela.<br/>Proszę użyć hasła składającego się z <b>10 lub więcej losowych znaków</b> lub <b>ośmiu lub więcej słów</b>. - + Encrypt wallet Zaszyfruj portfel - + This operation needs your wallet passphrase to unlock the wallet. Ta operacja wymaga hasła do portfela ażeby odblokować portfel. - + Unlock wallet Odblokuj portfel - + This operation needs your wallet passphrase to decrypt the wallet. Ta operacja wymaga hasła do portfela ażeby odszyfrować portfel. - + Decrypt wallet Odszyfruj portfel - + Change passphrase Zmień hasło - + Enter the old and new passphrase to the wallet. Podaj stare i nowe hasło do portfela. - + Confirm wallet encryption Potwierdź szyfrowanie portfela - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - OSTRZEŻENIE: Jeśli zaszyfrujesz portfel i zgubisz hasło, wtedy <b>STRACISZ WSZYSTKIE SWOJE BITMONETY</b> -Czy na pewno chcesz zaszyfrować swój portfel? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Uwaga: Jeśli zaszyfrujesz swój portfel i zgubisz hasło to <b>STRACISZ WSZYSTKIE SWOJE CASINOCOIN'Y</b>! - - + + Are you sure you wish to encrypt your wallet? + Jesteś pewien, że chcesz zaszyfrować swój portfel? + + + + 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. + 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. + + + + + Warning: The Caps Lock key is on! + Uwaga: Klawisz Caps Lock jest włączony + + + + Wallet encrypted Portfel zaszyfrowany - - Bitcoin 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. - Program Bitcoin 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. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + Program CasinoCoin zamknie się aby dokończyć proces szyfrowania. Pamiętaj, że szyfrowanie portfela nie zabezpiecza w pełni Twoich casinocoinów przed kradzieżą przez wirusy lub trojany mogące zainfekować Twój komputer. - - - Warning: The Caps Lock key is on. - Ostrzeżenie: Caps Lock jest włączony. - - - - - - + + + + Wallet encryption failed Szyfrowanie portfela nie powiodło się - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Szyfrowanie portfela nie powiodło się z powodu wewnętrznego błędu. Twój portfel nie został zaszyfrowany. - - + + The supplied passphrases do not match. Podane hasła nie są takie same. - + Wallet unlock failed Odblokowanie portfela nie powiodło się - - - + + + The passphrase entered for the wallet decryption was incorrect. Wprowadzone hasło do odszyfrowania portfela jest niepoprawne. - + Wallet decryption failed Odszyfrowywanie portfela nie powiodło się - - Wallet passphrase was succesfully changed. - Hasło do portfela zostało pomyślnie zmienione. + + Wallet passphrase was successfully changed. + Hasło portfela zostało pomyślnie zmienione. BitcoinGUI - - Bitcoin Wallet - Portfel Bitcoin - - - + Sign &message... Podpisz wiado&mość... - - Show/Hide &Bitcoin - Pokaż/Ukryj &Bitcoin - - - + Synchronizing with network... Synchronizacja z siecią... - + &Overview P&odsumowanie - + Show general overview of wallet Pokazuje ogólny zarys portfela - + &Transactions &Transakcje - + Browse transaction history Przeglądaj historię transakcji - - &Address Book - Książka &adresowa - - - + Edit the list of stored addresses and labels Edytuj listę zapisanych adresów i i etykiet - - &Receive coins - Odbie&rz monety - - - + Show the list of addresses for receiving payments Pokaż listę adresów do otrzymywania płatności - - &Send coins - Wy&syłka monet - - - - Prove you control an address - Udowodnij, że kontrolujesz adres - - - + E&xit &Zakończ - + Quit application Zamknij program - - &About %1 - &O %1 + + Show information about CasinoCoin + Pokaż informację o CasinoCoin - - Show information about Bitcoin - Pokaż informację o Bitcoin - - - + About &Qt O &Qt - + Show information about Qt Pokazuje informacje o Qt - + &Options... &Opcje... - + &Encrypt Wallet... Zaszyfruj Portf&el - + &Backup Wallet... - + Wykonaj kopię zapasową... - + &Change Passphrase... - - - - - ~%n block(s) remaining - pozostał ~%n blokpozostało ~%n blokipozostało ~%n bloków + &Zmień hasło... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Importowanie bloków z dysku... - - &Export... - &Eksportuj... + + Reindexing blocks on disk... + Ponowne indeksowanie bloków na dysku... - - Send coins to a Bitcoin address - Wyślij monety na adres Bitcoin + + Send coins to a CasinoCoin address + Wyślij monety na adres CasinoCoin - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Zmienia opcje konfiguracji casinocoina - - Show or hide the Bitcoin window - Pokaż lub ukryj okno Bitcoin - - - - Export the data in the current tab to a file - Eksportuj dane z aktywnej karty do pliku - - - - Encrypt or decrypt wallet - Zaszyfruj lub odszyfruj portfel - - - + Backup wallet to another location Zapasowy portfel w innej lokalizacji - + Change the passphrase used for wallet encryption Zmień hasło użyte do szyfrowania portfela - + &Debug window - + &Okno debudowania - + Open debugging and diagnostic console - + Otwórz konsolę debugowania i diagnostyki - + &Verify message... - + &Zweryfikuj wiadomość... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Portfel + + + + &Send + Wyślij + + + + &Receive + Odbie&rz + + + + &Addresses + &Adresy + + + + &About CasinoCoin + O CasinoCoin + + + + &Show / Hide + &Pokaż / Ukryj + + + + Show or hide the main Window + Pokazuje lub ukrywa główne okno + + + + Encrypt the private keys that belong to your wallet + Szyfruj klucze prywatne, które są powiązane z twoim portfelem + + + + Sign messages with your CasinoCoin addresses to prove you own them + Podpisz wiadomości swoim adresem aby udowodnić jego posiadanie + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Zweryfikuj wiadomość, aby upewnić się, że została podpisana odpowiednim adresem CasinoCoin. + + + &File &Plik - + &Settings P&referencje - + &Help Pomo&c - + Tabs toolbar Pasek zakładek - - Actions toolbar - Pasek akcji - - - - + + [testnet] [testnet] - - - Bitcoin client - Bitcoin klient + + CasinoCoin client + CasinoCoin klient - - %n active connection(s) to Bitcoin network - %n aktywne połączenie do sieci Bitcoin%n aktywne połączenia do sieci Bitcoin%n aktywnych połączeń do sieci Bitcoin + + %n active connection(s) to CasinoCoin network + %n aktywne połączenie do sieci CasinoCoin%n aktywne połączenia do sieci CasinoCoin%n aktywnych połączeń do sieci CasinoCoin - - Downloaded %1 blocks of transaction history. + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + Przetworzono (w przybliżeniu) %1 z %2 bloków historii transakcji. + + + + Processed %1 blocks of transaction history. Pobrano %1 bloków z historią transakcji. - - %n second(s) ago - %n sekundę temu%n sekundy temu%n sekund temu + + %n hour(s) + %n godzina%n godzin%n godzin - - %n minute(s) ago - %n minutę temu%n minuty temu%n minut temu + + %n day(s) + %n dzień%n dni%n dni - - %n hour(s) ago - %n godzinę temu%n godziny temu%n godzin temu - - - - %n day(s) ago - %n dzień temu%n dni temu%n dni temu + + %n week(s) + %n tydzień%n tygodni%n tygodni - + + %1 behind + + + + + Last received block was generated %1 ago. + Ostatni otrzymany blok został wygenerowany %1 temu. + + + + Transactions after this will not yet be visible. + + + + + Error + Błąd + + + + Warning + Ostrzeżenie + + + + Information + Informacja + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Transakcja przekracza limit. Możesz wysłać ją płacąc prowizję %1, która zostaje przekazana do węzłów, które ją prześlą i pomoże wspierać sieć CasinoCoin. Czy chcesz zapłacić prowizję? + + + Up to date Aktualny - + Catching up... Łapanie bloków... - - Last received block was generated %1. - Ostatnio otrzymany blok została wygenerowany %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Transakcja przekracza limit. Możesz wysłać ją płacąc prowizję %1, która zostaje przekazana do węzłów, które ją prześlą i pomoże wspierać sieć Bitcoin. Czy chcesz zapłacić prowizję? - - - + Confirm transaction fee Potwierdź prowizję transakcyjną - + Sent transaction Transakcja wysłana - + Incoming transaction Transakcja przychodząca - + Date: %1 Amount: %2 Type: %3 @@ -587,538 +648,485 @@ Adres: %4 - + + + URI handling + Obsługa URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI nie może zostać przetworzony! Prawdopodobnie błędny adres CasinoCoin bądź nieprawidłowe parametry URI. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Portfel jest <b>zaszyfrowany</b> i obecnie <b>niezablokowany</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Portfel jest <b>zaszyfrowany</b> i obecnie <b>zablokowany</b> - - Backup Wallet - Kopia Zapasowa Portfela - - - - Wallet Data (*.dat) - Dane Portfela (*.dat) - - - - Backup Failed - Kopia Zapasowa Nie Została Wykonana - - - - There was an error trying to save the wallet data to the new location. - Wystąpił błąd podczas próby zapisu portfela do nowej lokalizacji. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Błąd krytyczny. CasinoCoin nie może kontynuować bezpiecznie więc zostanie zamknięty. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Wyświetlanie - - - - default - domyślny - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Wybierz podział jednostki pokazywany w interfejsie oraz podczas wysyłania monet - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - Ostrzeżenie - - - - This setting will take effect after restarting Bitcoin. - + Sieć Alert EditAddressDialog - + Edit Address Edytuj adres - + &Label &Etykieta - + The label associated with this address book entry Etykieta skojarzona z tym wpisem w książce adresowej - + &Address &Adres - + The address associated with this address book entry. This can only be modified for sending addresses. Ten adres jest skojarzony z wpisem w książce adresowej. Może być zmodyfikowany jedynie dla adresów wysyłających. - + New receiving address Nowy adres odbiorczy - + New sending address Nowy adres wysyłania - + Edit receiving address Edytuj adres odbioru - + Edit sending address Edytuj adres wysyłania - + The entered address "%1" is already in the address book. Wprowadzony adres "%1" już istnieje w książce adresowej. - - The entered address "%1" is not a valid Bitcoin address. - Wprowadzony adres "%1" nie jest poprawnym adresem Bitcoin. + + The entered address "%1" is not a valid CasinoCoin address. + Wprowadzony adres "%1" nie jest poprawnym adresem CasinoCoin. - + Could not unlock wallet. Nie można było odblokować portfela. - + New key generation failed. Tworzenie nowego klucza nie powiodło się. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version wersja - + Usage: Użycie: - - options - + + command-line options + opcje konsoli - + UI options - + UI opcje - + Set language, for example "de_DE" (default: system locale) Ustaw Język, na przykład "pl_PL" (domyślnie: systemowy) - + Start minimized Uruchom zminimalizowany - + Show splash screen on startup (default: 1) Pokazuj okno powitalne przy starcie (domyślnie: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Opcje + + + + &Main + Główne + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee - Płać prowizję za t&ransakcje + Płać prowizję za transakcje - - Main - Główny + + Automatically start CasinoCoin after logging in to the system. + Automatycznie uruchamia CasinoCoin po zalogowaniu do systemu. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Opcjonalna prowizja za transakcje za kB, wspomaga ona szybkość przebiegu transakcji. Większość transakcji jest 1 kB. Zalecana prowizja 0.01 . + + &Start CasinoCoin on system login + Uruchamiaj CasinoCoin wraz z zalogowaniem do &systemu - - &Start Bitcoin on system login - + + Reset all client options to default. + Przywróć domyślne wszystkie ustawienia klienta. - - Automatically start Bitcoin after logging in to the system - Automatycznie uruchom Bitcoin po zalogowaniu do systemu + + &Reset Options + Z&resetuj Ustawienia - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + &Sieć - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Możesz podpisywać wiadomości swoimi adresami aby udowodnić, że jesteś ich właścicielem. Uważaj, aby nie podpisywać niczego co wzbudza Twoje podejrzenia, ponieważ ktoś może stosować phishing próbując nakłonić Cię do ich podpisania. Akceptuj i podpisuj tylko w pełni zrozumiałe komunikaty i wiadomości. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automatycznie otwiera port klienta CasinoCoin na routerze. Ta opcja dzieła tylko jeśli twój router wspiera UPnP i jest ono włączone. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Wybierz adres z książki adresowej - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Wklej adres ze schowka - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Wprowadź wiadomość, którą chcesz podpisać, tutaj - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Kliknij "Podpisz Wiadomość" żeby uzyskać podpis - - - - Sign a message to prove you own this address - Podpisz wiadomość aby dowieść, że ten adres jest twój - - - - &Sign Message - Podpi&sz Wiadomość - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Wprowadź adres Bitcoin (np. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Błąd podpisywania - - - - %1 is not a valid address. - %1 nie jest poprawnym adresem. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Klucz prywatny dla %1 jest niedostępny. - - - - Sign failed - Podpisywanie nie powiodło się. - - - - NetworkOptionsPage - - - Network - Sieć - - - + Map port using &UPnP Mapuj port używając &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automatycznie otwiera port klienta Bitcoin na routerze. Ta opcja dzieła tylko jeśli twój router wspiera UPnP i jest ono włączone. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Podłącz się do sieci CasinoCoin przez proxy SOCKS (np. gdy łączysz się poprzez Tor'a) - - &Connect through SOCKS4 proxy: - Połącz przez proxy SO&CKS4: + + &Connect through SOCKS proxy: + &Połącz się przez proxy SOCKS - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Łączy się z siecią Bitcoin przez proxy SOCKS4 (np. kiedy łączysz się przez Tor) - - - + Proxy &IP: Proxy &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Adres IP serwera proxy (np. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Port proxy (np. 1234) + + &Port: + &Port: - - - OptionsDialog - - Options - Opcje + + Port of the proxy (e.g. 9050) + Port proxy (np. 9050) + + + + SOCKS &Version: + Wersja &SOCKS + + + + SOCKS version of the proxy (e.g. 5) + SOCKS wersja serwera proxy (np. 5) + + + + &Window + &Okno + + + + Show only a tray icon after minimizing the window. + Pokazuj tylko ikonę przy zegarku po zminimalizowaniu okna. + + + + &Minimize to the tray instead of the taskbar + &Minimalizuj do paska przy zegarku zamiast do paska zadań + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimalizuje zamiast zakończyć działanie programu przy zamykaniu okna. Kiedy ta opcja jest włączona, program zakończy działanie po wybieraniu Zamknij w menu. + + + + M&inimize on close + M&inimalizuj przy zamknięciu + + + + &Display + &Wyświetlanie + + + + User Interface &language: + Język &Użytkownika: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Można tu ustawić język interfejsu uzytkownika. Żeby ustawienie przyniosło skutek trzeba uruchomić ponownie CasinoCoin. + + + + &Unit to show amounts in: + &Jednostka pokazywana przy kwocie: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Wybierz podział jednostki pokazywany w interfejsie oraz podczas wysyłania monet + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Pokazuj adresy CasinoCoin na liście transakcji. + + + + &Display addresses in transaction list + &Wyświetlaj adresy w liście transakcji + + + + &OK + &OK + + + + &Cancel + &Anuluj + + + + &Apply + Z&astosuj + + + + default + domyślny + + + + Confirm options reset + Potwierdź reset ustawień + + + + Some settings may require a client restart to take effect. + Niektóre ustawienia mogą wymagać ponownego uruchomienia klienta, żeby zacząć działać. + + + + Do you want to proceed? + Czy chcesz kontynuować? + + + + + Warning + Ostrzeżenie + + + + + This setting will take effect after restarting CasinoCoin. + To ustawienie zostanie zastosowane po restarcie CasinoCoin + + + + The supplied proxy address is invalid. + Adres podanego proxy jest nieprawidłowy OverviewPage - + Form Formularz - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Wyświetlana informacja może być nieaktualna. Twój portfel synchronizuje się automatycznie z siecią casinocoin, zaraz po tym jak uzyskano połączenie, ale proces ten nie został jeszcze ukończony. - + Balance: Saldo: - - Number of transactions: - Liczba transakcji: - - - + Unconfirmed: Niepotwierdzony: - + Wallet Portfel - + + Immature: + Niedojrzały: + + + + Mined balance that has not yet matured + Balans wydobycia, który jeszcze nie dojrzał + + + <b>Recent transactions</b> <b>Ostatnie transakcje</b> - + Your current balance Twoje obecne saldo - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Suma transakcji, które nie zostały jeszcze potwierdzone, i które nie zostały wliczone do twojego obecnego salda - - Total number of transactions in wallet - Całkowita liczba transakcji w portfelu - - - - + + out of sync + desynchronizacja + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog Okno Dialogowe Kodu QR - - QR Code - Kod QR - - - + Request Payment Prośba o płatność - + Amount: Kwota: - - BTC - BTC - - - + Label: Etykieta: - + Message: Wiadomość: - + &Save As... Zapi&sz jako... - + Error encoding URI into QR Code. Błąd kodowania URI w Kodzie QR. - - Resulting URI too long, try to reduce the text for label / message. - + + The entered amount is invalid, please check. + Podana ilość jest nieprawidłowa, proszę sprawdzić - + + Resulting URI too long, try to reduce the text for label / message. + Wynikowy URI jest zbyt długi, spróbuj zmniejszyć tekst etykiety / wiadomości + + + Save QR Code Zapisz Kod QR - + PNG Images (*.png) Obraz PNG (*.png) @@ -1126,453 +1134,713 @@ Adres: %4 RPCConsole - - Bitcoin debug window - - - - + Client name Nazwa klienta - - - - - - - - - + + + + + + + + + + N/A NIEDOSTĘPNE - + Client version Wersja klienta - + &Information - + &Informacje - - Client - Klient + + Using OpenSSL version + Używana wersja OpenSSL - + Startup time - + Czas uruchomienia - + Network Sieć - + Number of connections Liczba połączeń - + On testnet - + W sieci testowej - + Block chain - + Ciąg bloków - + Current number of blocks Aktualna liczba bloków - + Estimated total blocks Szacowana ilość bloków - + Last block time - + Czas ostatniego bloku - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open &Otwórz - + + Command-line options + Opcje konsoli + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Pokaż pomoc CasinoCoin-Qt, aby zobaczyć listę wszystkich opcji linii poleceń + + + + &Show + &Pokaż + + + &Console - + &Konsola - + Build date + Data kompilacji + + + + CasinoCoin - Debug window + CasinoCoin - Okno debudowania + + + + CasinoCoin Core + Rdzeń BitCoin + + + + Debug log file - + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - Wyczyść konsole + Wyczyść konsolę - - Welcome to the Bitcoin RPC console. - Witam w konsoli Bitcoin RPC + + Welcome to the CasinoCoin RPC console. + Witam w konsoli CasinoCoin RPC - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Użyj strzałek do przewijania historii i <b>Ctrl-L</b> aby wyczyścić ekran - + Type <b>help</b> for an overview of available commands. - + Wpisz <b>help</b> aby uzyskać listę dostępnych komend SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Wyślij płatność - + Send to multiple recipients at once Wyślij do wielu odbiorców na raz - - &Add Recipient - + + Add &Recipient + Dodaj Odbio&rce - + Remove all transaction fields Wyczyść wszystkie pola transakcji - + Clear &All - + Wyczyść &wszystko - + Balance: Saldo: - + 123.456 BTC 123.456 BTC - + Confirm the send action Potwierdź akcję wysyłania - - &Send + + S&end Wy&syłka - + <b>%1</b> to %2 (%3) <b>%1</b> do %2 (%3) - + Confirm send coins Potwierdź wysyłanie monet - + Are you sure you want to send %1? Czy na pewno chcesz wysłać %1? - + and i - - The recepient address is not valid, please recheck. - Adres odbiorcy jest niepoprawny, proszę go sprawdzić. + + The recipient address is not valid, please recheck. + Adres odbiorcy jest nieprawidłowy, proszę poprawić - + The amount to pay must be larger than 0. - Kwota do zapłacenie musi być większa od 0. + Kwota do zapłacenia musi być większa od 0. - + The amount exceeds your balance. Kwota przekracza twoje saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + Suma przekracza twoje saldo, gdy doliczymy %1 prowizji transakcyjnej. - + Duplicate address found, can only send to each address once per send operation. - + Znaleziono powtórzony adres, można wysłać tylko raz na każdy adres podczas operacji wysyłania. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Błąd: Tworzenie transakcji zakończone niepowodzeniem! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Błąd: transakcja została odrzucona. Może się to zdarzyć, gdy monety z Twojego portfela zostały już wydane, na przykład gdy używałeś kopii wallet.dat i casinocoiny które tam wydałeś nie zostały jeszcze odjęte z portfela z którego teraz korzystasz. SendCoinsEntry - + Form Formularz - + A&mount: Su&ma: - + Pay &To: - Płać &Do: + Zapłać dla: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adres, na który wysłasz płatności (np. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Wprowadź etykietę dla tego adresu by dodać go do książki adresowej - + &Label: &Etykieta: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adres do wysłania należności do (np. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Wybierz adres z książki adresowej - + Alt+A Alt+A - + Paste address from clipboard Wklej adres ze schowka - + Alt+P Alt+P - + Remove this recipient Usuń tego odbiorce - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Wprowadź adres Bitcoin (np. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Wprowadź adres CasinoCoin (np. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Podpisy - Podpisz / zweryfikuj wiadomość + + + + &Sign Message + Podpi&sz Wiadomość + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Możesz podpisywać wiadomości swoimi adresami aby udowodnić, że jesteś ich właścicielem. Uważaj, aby nie podpisywać niczego co wzbudza Twoje podejrzenia, ponieważ ktoś może stosować phishing próbując nakłonić Cię do ich podpisania. Akceptuj i podpisuj tylko w pełni zrozumiałe komunikaty i wiadomości. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Wprowadź adres CasinoCoin (np. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Wybierz adres z książki kontaktowej + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Wklej adres ze schowka + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Wprowadź wiadomość, którą chcesz podpisać, tutaj + + + + Signature + Podpis + + + + Copy the current signature to the system clipboard + Kopiuje aktualny podpis do schowka systemowego + + + + Sign the message to prove you own this CasinoCoin address + Podpisz wiadomość aby dowieść, że ten adres jest twój + + + + Sign &Message + Podpisz Wiado&mość + + + + Reset all sign message fields + Zresetuj wszystkie pola podpisanej wiadomości + + + + + Clear &All + Wyczyść &wszystko + + + + &Verify Message + &Zweryfikuj wiadomość + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Wprowadź adres CasinoCoin (np. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Zweryfikuj wiadomość, aby upewnić się, że została podpisana odpowiednim adresem CasinoCoin. + + + + Verify &Message + Zweryfikuj Wiado&mość + + + + Reset all verify message fields + Resetuje wszystkie pola weryfikacji wiadomości + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Wprowadź adres CasinoCoin (np. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Kliknij "Podpisz Wiadomość" żeby uzyskać podpis + + + + Enter CasinoCoin signature + Wprowadź podpis CasinoCoin + + + + + The entered address is invalid. + Podany adres jest nieprawidłowy. + + + + + + + Please check the address and try again. + Proszę sprawdzić adres i spróbować ponownie. + + + + + The entered address does not refer to a key. + Wprowadzony adres nie odnosi się do klucza. + + + + Wallet unlock was cancelled. + Odblokowanie portfela zostało anulowane. + + + + Private key for the entered address is not available. + Klucz prywatny dla podanego adresu nie jest dostępny + + + + Message signing failed. + Podpisanie wiadomości nie powiodło się + + + + Message signed. + Wiadomość podpisana. + + + + The signature could not be decoded. + Podpis nie może zostać zdekodowany. + + + + + Please check the signature and try again. + Sprawdź podpis i spróbuj ponownie. + + + + The signature did not match the message digest. + + + + + Message verification failed. + Weryfikacja wiadomości nie powiodła się. + + + + Message verified. + Wiadomość zweryfikowana. + + + + SplashScreen + + + The CasinoCoin developers + Deweloperzy CasinoCoin + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Otwórz dla %1 bloków - - - + Open until %1 Otwórz do %1 - - %1/offline? - %1/offline? + + %1/offline + %1/offline - + %1/unconfirmed %1/niezatwierdzone - + %1 confirmations %1 potwierdzeń - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , emitowany przez %n węzeł, emitowany przez %n węzły, emitowany przez %n węzłów - + + Date + Data + + + + Source + Źródło + + + + Generated + Wygenerowano + + + + + From + Od + + + + + + To + Do + + + + + own address + własny adres + + + + label + etykieta + + + + + + + + Credit + Przypisy + + + + matures in %n more block(s) + + + + + not accepted + niezaakceptowane + + + + + + + Debit + Debet + + + + Transaction fee + Prowizja transakcji + + + + Net amount + Kwota netto + + + + Message + Wiadomość + + + + Comment + Komentarz + + + + Transaction ID + ID transakcji + + + + Generated coins must mature 120 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. + Wygenerowane monety muszą zaczekać 120 bloków zanim będzie można je wydać. Kiedy wygenerowałeś ten blok, został on wyemitowany do sieci, aby dodać go do łańcucha bloków. Jeśli to się nie powiedzie nie zostanie on zaakceptowany i wygenerowanych monet nie będzie można wysyłać. Może się to czasami zdarzyć jeśli inny węzeł wygeneruje blok tuż przed tobą. + + + + Debug information + Informacje debugowania + + + + Transaction + Transakcja + + + + Inputs + Wejścia + + + + Amount + Kwota + + + + true + prawda + + + + false + fałsz + + + , has not been successfully broadcast yet , nie został jeszcze pomyślnie wyemitowany - - - , broadcast through %1 node - , emitowany przez %1 węzeł + + + Open for %n more block(s) + Otwórz dla %n blokuOtwórz dla %n następnych blokówOtwórz dla %n następnych bloków - - , broadcast through %1 nodes - , emitowany przez %1 węzły - - - - <b>Date:</b> - <b>Data:</b> - - - - <b>Source:</b> Generated<br> - <b>Źródło:</b> Wygenerowano<br> - - - - - <b>From:</b> - <b>Od:</b> - - - + unknown nieznany - - - - - <b>To:</b> - <b>Do:</b> - - - - (yours, label: - (twoje, etykieta: - - - - (yours) - (twoje) - - - - - - - <b>Credit:</b> - <b>Przypisy:</b> - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - (niezaakceptowane) - - - - - - <b>Debit:</b> - <b>Debet:</b> - - - - <b>Transaction fee:</b> - <b>Prowizja transakcyjna:</b> - - - - <b>Net amount:</b> - <b>Kwota netto:</b> - - - - Message: - Wiadomość: - - - - Comment: - Komentarz: - - - - Transaction ID: - ID transakcji: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Wygenerowane monety muszą zaczekać 120 bloków zanim będzie można je wydać. Kiedy wygenerowałeś ten blok, został on wyemitowany do sieci, aby dodać go do łańcucha bloków. Jeśli to się nie powiedzie nie zostanie on zaakceptowany i wygenerowanych monet nie będzie można wysyłać. Może się to czasami zdarzyć jeśli inny węzeł wygeneruje blok tuż przed tobą. - TransactionDescDialog - + Transaction details Szczegóły transakcji - + This pane shows a detailed description of the transaction Ten panel pokazuje szczegółowy opis transakcji @@ -1580,117 +1848,117 @@ Adres: %4 TransactionTableModel - + Date Data - + Type Typ - + Address Adres - + Amount Kwota - - Open for %n block(s) - Otwórz dla %n blokuOtwórz dla %n blokówOtwórz dla %n bloków + + Open for %n more block(s) + Otwórz dla %n następnych bloków - + Open until %1 Otwórz do %1 - + Offline (%1 confirmations) Offline (%1 potwierdzeń) - + Unconfirmed (%1 of %2 confirmations) Niezatwierdzony (%1 z %2 potwierdzeń) - + Confirmed (%1 confirmations) Zatwierdzony (%1 potwierdzeń) - - Mined balance will be available in %n more blocks - Wydobyta kwota będzie dostępna za %n blokWydobyta kwota będzie dostępna za %n blokówWydobyta kwota będzie dostępna za %n bloki + + Mined balance will be available when it matures in %n more block(s) + Balans wydobycia będzie dostępny zaraz po tym, jak dojrzeje. Pozostał %n blokBalans wydobycia będzie dostępny zaraz po tym, jak dojrzeje. Pozostało %n blokówBalans wydobycia będzie dostępny zaraz po tym, jak dojrzeje. Pozostało %n bloków - + This block was not received by any other nodes and will probably not be accepted! Ten blok nie został odebrany przez jakikolwiek inny węzeł i prawdopodobnie nie zostanie zaakceptowany! - + Generated but not accepted Wygenerowano ale nie zaakceptowano - + Received with Otrzymane przez - + Received from Odebrano od - + Sent to Wysłano do - + Payment to yourself Płatność do siebie - + Mined Wydobyto - + (n/a) (brak) - + Transaction status. Hover over this field to show number of confirmations. Status transakcji. Najedź na pole, aby zobaczyć liczbę potwierdzeń. - + Date and time that the transaction was received. Data i czas odebrania transakcji. - + Type of transaction. Rodzaj transakcji. - + Destination address of transaction. Adres docelowy transakcji. - + Amount removed from or added to balance. Kwota usunięta z lub dodana do konta. @@ -1698,820 +1966,973 @@ Adres: %4 TransactionView - - + + All Wszystko - + Today Dzisiaj - + This week W tym tygodniu - + This month W tym miesiącu - + Last month W zeszłym miesiącu - + This year W tym roku - + Range... Zakres... - + Received with Otrzymane przez - + Sent to Wysłano do - + To yourself Do siebie - + Mined Wydobyto - + Other Inne - + Enter address or label to search Wprowadź adres albo etykietę żeby wyszukać - + Min amount Min suma - + Copy address Kopiuj adres - + Copy label Kopiuj etykietę - + Copy amount Kopiuj kwotę - + + Copy transaction ID + Skopiuj ID transakcji + + + Edit label Edytuj etykietę - + Show transaction details Pokaż szczegóły transakcji - + Export Transaction Data Eksportuj Dane Transakcyjne - + Comma separated file (*.csv) CSV (rozdzielany przecinkami) - + Confirmed Potwierdzony - + Date Data - + Type Typ - + Label Etykieta - + Address Adres - + Amount Kwota - + ID ID - + Error exporting Błąd podczas eksportowania - + Could not write to file %1. Błąd zapisu do pliku %1. - + Range: Zakres: - + to do - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Skopiuj aktualnie wybrany adres do schowka - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Wysyłanie... + + Send Coins + Wyślij płatność - WindowOptionsPage + WalletView - - Window - Okno + + &Export + &Eksportuj - - &Minimize to the tray instead of the taskbar - &Minimalizuj do paska przy zegarku zamiast do paska zadań + + Export the data in the current tab to a file + Eksportuj dane z aktywnej karty do pliku - - Show only a tray icon after minimizing the window - Pokazuje tylko ikonę przy zegarku po zminimalizowaniu okna + + Backup Wallet + Kopia Zapasowa Portfela - - M&inimize on close - M&inimalizuj przy zamknięciu + + Wallet Data (*.dat) + Dane Portfela (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimalizuje zamiast zakończyć działanie programu przy zamykaniu okna. Kiedy ta opcja jest włączona, program zakończy działanie po wybieraniu Zamknij w menu. + + Backup Failed + Nie udało się wykonać kopii zapasowej + + + + There was an error trying to save the wallet data to the new location. + Wystąpił błąd przy zapisywaniu portfela do nowej lokalizacji. + + + + Backup Successful + Wykonano Kopię Zapasową + + + + The wallet data was successfully saved to the new location. + Dane portfela zostały poprawnie zapisane w nowym miejscu. bitcoin-core - - Bitcoin version - Wersja Bitcoin + + CasinoCoin version + Wersja CasinoCoin - + Usage: Użycie: - - Send command to -server or bitcoind - Wyślij polecenie do -server lub bitcoind + + Send command to -server or casinocoind + Wyślij polecenie do -server lub casinocoind - + List commands Lista poleceń - + Get help for a command Uzyskaj pomoc do polecenia - + Options: Opcje: - - Specify configuration file (default: bitcoin.conf) - Wskaż plik konfiguracyjny (domyślnie: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Wskaż plik konfiguracyjny (domyślnie: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Wskaż plik pid (domyślnie: bitcoin.pid) + + Specify pid file (default: casinocoind.pid) + Wskaż plik pid (domyślnie: casinocoin.pid) - - Generate coins - Generuj monety - - - - Don't generate coins - Nie generuj monet - - - + Specify data directory Wskaż folder danych - + Set database cache size in megabytes (default: 25) - + Ustaw rozmiar w megabajtach cache-u bazy danych (domyślnie: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Nasłuchuj połączeń na <port> (domyślnie: 47950 lub testnet: 17950) - - Specify connection timeout (in milliseconds) - Wskaż czas oczekiwania bezczynności połączenia (w milisekundach) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Nasłuchuj połączeń na <port> (domyślnie: 8333 lub testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Utrzymuj maksymalnie <n> połączeń z peerami (domyślnie: 125) - - Connect only to the specified node - Łącz tylko do wskazanego węzła - - - + Connect to a node to retrieve peer addresses, and disconnect - + Podłącz się do węzła aby otrzymać adresy peerów i rozłącz - + Specify your own public address - + Podaj swój publiczny adres - - Only connect to nodes in network <net> (IPv4 or IPv6) - Łącz tylko z węzłami w sieci <net> (IPv4 lub IPv6) - - - - Try to discover public IP address (default: 1) - Próbuj odkryć publiczny adres IP (domyślnie: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Próg po którym nastąpi rozłączenie nietrzymających się zasad peerów (domyślnie: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + Czas w sekundach, przez jaki nietrzymający się zasad peerzy nie będą mogli ponownie się podłączyć (domyślnie: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maksymalny bufor odbioru na połączenie, <n>*1000 bajtów (domyślnie: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Wystąpił błąd podczas ustawiania portu RPC %u w tryb nasłuchu: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maksymalny bufor wysyłu na połączenie, <n>*1000 bajtów (domyślnie: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Nasłuchuj połączeń JSON-RPC na <port> (domyślnie: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Akceptuj linię poleceń oraz polecenia JSON-RPC - + Run in the background as a daemon and accept commands Uruchom w tle jako daemon i przyjmuj polecenia - + Use the test network Użyj sieci testowej - - Output extra debugging information + + Accept connections from outside (default: 1 if no -proxy or -connect) + Akceptuj połączenia z zewnątrz (domyślnie: 1 jeśli nie ustawiono -proxy lub -connect) + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, musisz ustawić rpcpassword w pliku konfiguracyjnym:⏎ +%s⏎ +Zalecane jest użycie losowego hasła:⏎ +rpcuser=casinocoinrpc⏎ +rpcpassword=%s⏎ +(nie musisz pamiętać tego hasła)⏎ +Użytkownik i hasło nie mogą być takie same.⏎ +Jeśli plik nie istnieje, utwórz go z uprawnieniami tylko-do-odczytu dla właściciela.⏎ +Zalecane jest ustawienie alertnotify aby poinformować o problemach:⏎ +na przykład: alertnotify=echo %%s | mail -s "Alarm CasinoCoin" admin@foo.com⏎ + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Wystąpił błąd podczas ustawiania portu RPC %u w tryb nasłuchu dla IPv6, korzystam z IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Skojarz z podanym adresem. Użyj formatu [host]:port dla IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Nie można zablokować folderu danych %s. CasinoCoin prawdopodobnie już działa. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Uruchom polecenie przy otrzymaniu odpowiedniego powiadomienia (%s w poleceniu jest podstawiane za komunikat) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Wykonaj polecenie, kiedy transakcja portfela ulegnie zmianie (%s w poleceniu zostanie zastąpione przez TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Ustaw maksymalny rozmiar transakcji o wysokim priorytecie/niskiej prowizji w bajtach (domyślnie: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Ostrzeżenie: -paytxfee jest bardzo duży. To jest prowizja za transakcje, którą płacisz, gdy wysyłasz monety. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Uwaga: Wyświetlone transakcje mogą nie być poprawne! Możliwe, że potrzebujesz aktualizacji bądź inne węzły jej potrzebują + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Uwaga: Sprawdź czy data i czas na Twoim komputerze są prawidłowe! Jeśli nie to CasinoCoin nie będzie działał prawidłowo. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Ostrzeżenie: błąd odczytu wallet.dat! Wszystkie klucze zostały odczytane, ale może brakować pewnych danych transakcji lub wpisów w książce adresowej lub mogą one być nieprawidłowe. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Ostrzeżenie: Odtworzono dane z uszkodzonego pliku wallet.dat! Oryginalny wallet.dat został zapisany jako wallet.{timestamp}.bak w %s; jeśli twoje saldo lub transakcje są niepoprawne powinieneś odtworzyć kopię zapasową. + + + + Attempt to recover private keys from a corrupt wallet.dat + Próbuj odzyskać klucze prywatne z uszkodzonego wallet.dat + + + + Block creation options: + Opcje tworzenia bloku: + + + + Connect only to the specified node(s) + Łącz tylko do wskazanego węzła + + + + Corrupted block database detected + Wykryto uszkodzoną bazę bloków + + + + Discover own IP address (default: 1 when listening and no -externalip) + Odkryj własny adres IP (domyślnie: 1 kiedy w trybie nasłuchu i brak -externalip ) + + + + Do you want to rebuild the block database now? + Czy chcesz teraz przebudować bazę bloków? + + + + Error initializing block database + Błąd inicjowania bloku bazy danych + + + + Error initializing wallet database environment %s! + Błąd inicjowania środowiska bazy portfela %s! + + + + Error loading block database + Błąd ładowania bazy bloków + + + + Error opening block database + Błąd ładowania bazy bloków + + + + Error: Disk space is low! + Błąd: Mało miejsca na dysku! + + + + Error: Wallet locked, unable to create transaction! + Błąd: Zablokowany portfel, nie można utworzyć transakcji! + + + + Error: system error: + Błąd: błąd systemu: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Próba otwarcia jakiegokolwiek portu nie powiodła się. Użyj -listen=0 jeśli tego chcesz. + + + + Failed to read block info + Nie udało się odczytać informacji bloku + + + + Failed to read block + Nie udało się odczytać bloku. + + + + Failed to sync block index + Nie udało się zsynchronizować indeksu bloków. + + + + Failed to write block index + Nie udało się zapisać indeksu bloków. + + + + Failed to write block info + Nie udało się zapisać informacji bloku + + + + Failed to write block + Nie udało się zapisać bloku + + + + Failed to write file info + + + + + Failed to write to coin database + Nie udało się zapisać do bazy monet + + + + Failed to write transaction index + Nie udało się zapisać indeksu transakcji + + + + Failed to write undo data + Nie udało się zapisać danych odtwarzających + + + + Find peers using DNS lookup (default: 1 unless -connect) + Wyszukaj połączenia wykorzystując zapytanie DNS (domyślnie 1 jeśli nie użyto -connect) + + + + Generate coins (default: 0) + Generuj monety (domyślnie: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Ile bloków sprawdzić przy starcie (domyślnie: 288, 0 = wszystkie) + + + + How thorough the block verification is (0-4, default: 3) + Jak dokładna jest weryfikacja bloku (0-4, domyślnie: 3) + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + Odbuduj indeks łańcucha bloków z obecnych plików blk000??.dat + + + + Set the number of threads to service RPC calls (default: 4) + Ustaw liczbę wątków do odwołań RPC (domyślnie: 4) + + + + Verifying blocks... + Weryfikacja bloków... + + + + Verifying wallet... + Weryfikacja portfela... + + + + Imports blocks from external blk000??.dat file + Importuj bloki z zewnętrznego pliku blk000??.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Ustaw liczbę wątków skryptu weryfikacji (do 16, 0 = auto, <0 = zostawia taką ilość rdzenie wolnych, domyślnie: 0) + + + + Information + Informacja + + + + Invalid -tor address: '%s' + Nieprawidłowy adres -tor: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + Utrzymuj pełen indeks transakcji (domyślnie: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maksymalny bufor odbioru na połączenie, <n>*1000 bajtów (domyślnie: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maksymalny bufor wysyłu na połączenie, <n>*1000 bajtów (domyślnie: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Akceptuj tylko łańcuch bloków zgodny z wbudowanymi punktami kontrolnymi (domyślnie: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Łącz z węzłami tylko w sieci <net> (IPv4, IPv6 lub Tor) + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + Prepend debug output with timestamp - + Poprzedź informacje debugowania znacznikiem czasowym - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opcje SSL: (odwiedź CasinoCoin Wiki w celu uzyskania instrukcji) + + + + Select the version of socks proxy to use (4-5, default: 5) + Wybierz używaną wersje socks serwera proxy (4-5, domyślnie:5) + + + Send trace/debug info to console instead of debug.log file Wyślij informację/raport do konsoli zamiast do pliku debug.log. - + Send trace/debug info to debugger Wyślij informację/raport do debuggera. - + + Set maximum block size in bytes (default: 250000) + Ustaw maksymalny rozmiar bloku w bajtach (domyślnie: 250000) + + + + Set minimum block size in bytes (default: 0) + Ustaw minimalny rozmiar bloku w bajtach (domyślnie: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Zmniejsz plik debug.log przy starcie programu (domyślnie: 1 jeśli nie użyto -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Wskaż czas oczekiwania bezczynności połączenia w milisekundach (domyślnie: 5000) + + + + System error: + Błąd systemu: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Używaj UPnP do mapowania portu nasłuchu (domyślnie: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Używaj UPnP do mapowania portu nasłuchu (domyślnie: 1 gdy nasłuchuje) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + Username for JSON-RPC connections Nazwa użytkownika dla połączeń JSON-RPC - + + Warning + Ostrzeżenie + + + + Warning: This version is obsolete, upgrade required! + Uwaga: Ta wersja jest przestarzała, aktualizacja wymagana! + + + + You need to rebuild the databases using -reindex to change -txindex + Musisz przebudować bazę używając parametru -reindex aby zmienić -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat uszkodzony, odtworzenie się nie powiodło + + + Password for JSON-RPC connections Hasło do połączeń JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - Nasłuchuj połączeń JSON-RPC na <port> (domyślnie: 8332) - - - + Allow JSON-RPC connections from specified IP address Przyjmuj połączenia JSON-RPC ze wskazanego adresu IP - + Send commands to node running on <ip> (default: 127.0.0.1) Wysyłaj polecenia do węzła działającego na <ip> (domyślnie: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Wykonaj polecenie kiedy najlepszy blok ulegnie zmianie (%s w komendzie zastanie zastąpione przez hash bloku) - + Upgrade wallet to latest format - + Zaktualizuj portfel do najnowszego formatu. - + Set key pool size to <n> (default: 100) Ustaw rozmiar puli kluczy na <n> (domyślnie: 100) - + Rescan the block chain for missing wallet transactions Przeskanuj blok łańcuchów żeby znaleźć zaginione transakcje portfela - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -opcje SSL: (sprawdź Bitcoin Wiki dla instrukcje konfiguracji SSL) - - - + Use OpenSSL (https) for JSON-RPC connections Użyj OpenSSL (https) do połączeń JSON-RPC - + Server certificate file (default: server.cert) Plik certyfikatu serwera (domyślnie: server.cert) - + Server private key (default: server.pem) Klucz prywatny serwera (domyślnie: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Aceptowalne szyfry (domyślnie: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - Ostrzeżenie: mało miejsca na dysku - - - + This help message Ta wiadomość pomocy - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Nie można zablokować folderu danych %s. Bitcoin prawdopodobnie już działa. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Nie można przywiązać %s na tym komputerze (bind returned error %d, %s) - + Connect through socks proxy - + Łączy przez proxy socks - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - Nie używaj proxy do połączeń z siecią <net> (IPv4 lub IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Zezwól -addnode, -seednode i -connect na łączenie się z serwerem DNS - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... Wczytywanie adresów... - - Error loading blkindex.dat - Błąd ładownia blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Błąd ładowania wallet.dat: Uszkodzony portfel - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Błąd ładowania wallet.dat: Portfel wymaga nowszej wersji Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Błąd ładowania wallet.dat: Portfel wymaga nowszej wersji CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Portfel wymaga przepisania: zrestartuj Bitcoina żeby ukończyć + + Wallet needed to be rewritten: restart CasinoCoin to complete + Portfel wymaga przepisania: zrestartuj CasinoCoina żeby ukończyć - + Error loading wallet.dat Błąd ładowania wallet.dat - + Invalid -proxy address: '%s' - + Nieprawidłowy adres -proxy: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Nieznana sieć w -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Nieznana wersja proxy w -socks: %i - + Cannot resolve -bind address: '%s' - + Nie można uzyskać adresu -bind: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Nie można uzyskać adresu -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Nieprawidłowa kwota dla -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Błąd: Tworzenie transakcji nie powiodło się - - - - Sending... - Wysyłanie... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Błąd: transakcja została odrzucona. Może się to zdarzyć, gdy monety z Twojego portfela zostały już wydane, na przykład gdy używałeś kopii wallet.dat i bitcoiny które tam wydałeś nie zostały jeszcze odjęte z portfela z którego teraz korzystasz. - - - + Invalid amount Nieprawidłowa kwota - + Insufficient funds Niewystarczające środki - + Loading block index... Ładowanie indeksu bloku... - + Add a node to connect to and attempt to keep the connection open - + Dodaj węzeł do łączenia się and attempt to keep the connection open - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Nie można przywiązać %s na tym komputerze. CasinoCoin prawdopodobnie już działa. - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - + Fee per KB to add to transactions you send - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... Wczytywanie portfela... - + Cannot downgrade wallet - + Nie można dezaktualizować portfela - - Cannot initialize keypool - - - - + Cannot write default address - + Nie można zapisać domyślnego adresu - + Rescanning... Ponowne skanowanie... - + Done loading Wczytywanie zakończone - + To use the %s option - + Aby użyć opcji %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - - - - + Error Błąd - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Ostrzeżenie: Proszę sprawdzić poprawność czasu i daty na tym komputerze. Jeśli czas jest zły Bitcoin może nie działać prawidłowo. + Musisz ustawić rpcpassword=<hasło> w pliku configuracyjnym: +%s +Jeżeli plik nie istnieje, utwórz go z uprawnieniami właściciela-tylko-do-odczytu. \ No newline at end of file diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 64e2923..0911005 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -3,140 +3,178 @@ AboutDialog - - About Bitcoin - Sobre o Bitcoin + + About CasinoCoin + Sobre o CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versão + + <b>CasinoCoin</b> version + Versão do <b>CasinoCoin</b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Desenvolvedores do Bitcoin - -Esse software é experimental. - -Distribuído sob a licença de software MIT/X11, veja o arquivo de licença anexo license.txt ou http://www.opensource.org/licenses/mit-license.php. - -Esse produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenSSL Toolkit (http://www.openssl.org/) e software criptográfico escrito por Eric Young (eay@cryptsoft.com) e software UPnP escrito por Thomas Bernard. + ⏎ +Este é um software experimental.⏎ +⏎ +Distribuido sob a licença de software MIT/X11, veja o arquivo anexo COPYING ou http://www.opensource.org/licenses/mit-license.php.⏎ +⏎ +Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenSSL Toolkit (http://www.openssl.org/), software de criptografia escrito por Eric Young (eay@cryptsoft.com) e sofware UPnP escrito por Thomas Bernard. + + + + Copyright + Copyright + + + + The CasinoCoin developers + Desenvolvedores do CasinoCoin AddressBookPage - + Address Book Catálogo de endereços - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Estes são os seus endereços Bitcoin para receber pagamentos. Você pode querer enviar um endereço diferente para cada remetente, para acompanhar quem está pagando. - - - + Double-click to edit address or label Clique duas vezes para editar o endereço ou o etiqueta - + Create a new address Criar um novo endereço - + Copy the currently selected address to the system clipboard Copie o endereço selecionado para a área de transferência do sistema - + &New Address - + &Novo endereço - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Estes são os seus endereços CasinoCoin para receber pagamentos. Você pode querer enviar um endereço diferente para cada remetente, para acompanhar quem está pagando. + + + &Copy Address - + &Copiar Endereço - + Show &QR Code Mostrar &QR Code - - Sign a message to prove you own this address - Assine uma mensagem para provar que você é o dono desse endereço + + Sign a message to prove you own a CasinoCoin address + Assine uma mensagem para provar que você é dono de um endereço CasinoCoin - - &Sign Message + + Sign &Message &Assinar Mensagem - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Excluir o endereço selecionado da lista. Apenas endereços de envio podem ser excluídos. + + Delete the currently selected address from the list + Excluir os endereços selecionados da lista - + + Export the data in the current tab to a file + Exportar os dados na aba atual para um arquivo + + + + &Export + &Exportar + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verificar mensagem para se assegurar que ela foi assinada pelo dono de um endereço CasinoCoin específico. + + + + &Verify Message + &Verificar Mensagem + + + &Delete &Excluir - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Estes são os seus endereços CasinoCoin para receber pagamentos. Você pode querer enviar um endereço diferente para cada remetente, para acompanhar quem está pagando. + + + Copy &Label - + Copiar &Etiqueta - + &Edit - + &Editar - + + Send &Coins + Enviar bit&coins + + + Export Address Book Data - Exportação de dados do Catálogo de Endereços + Exportar Catálogo de Endereços - + Comma separated file (*.csv) Arquivo separado por vírgulas (*. csv) - + Error exporting Erro ao exportar - + Could not write to file %1. - Could not write to file %1. + Não foi possível gravar no arquivo %1. AddressTableModel - + Label Rótulo - + Address Endereço - + (no label) (Sem rótulo) @@ -144,431 +182,460 @@ Esse produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS AskPassphraseDialog - + Passphrase Dialog - + Janela da Frase de Segurança - + Enter passphrase Digite a frase de segurança - + New passphrase Nova frase de segurança - + Repeat new passphrase Repita a nova frase de segurança - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Digite a nova frase de seguraça da sua carteira. <br/> Por favor, use uma frase de <b>10 ou mais caracteres aleatórios,</b> ou <b>oito ou mais palavras.</b> - + Encrypt wallet Criptografar carteira - + This operation needs your wallet passphrase to unlock the wallet. Esta operação precisa de sua frase de segurança para desbloquear a carteira. - + Unlock wallet Desbloquear carteira - + This operation needs your wallet passphrase to decrypt the wallet. Esta operação precisa de sua frase de segurança para descriptografar a carteira. - + Decrypt wallet Descriptografar carteira - + Change passphrase Alterar frase de segurança - + Enter the old and new passphrase to the wallet. Digite a frase de segurança antiga e nova para a carteira. - + Confirm wallet encryption Confirmar criptografia da carteira - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - AVISO: Se você criptografar sua carteira e perder sua senha, você vai <b>perder todos os seus BITCOINS!</b> Tem certeza de que deseja criptografar sua carteira? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Aviso: Se você criptografar sua carteira e perder sua senha, você vai <b>perder todos os seus CASINOCOINS!</b> - - + + Are you sure you wish to encrypt your wallet? + Tem certeza de que deseja criptografar sua carteira? + + + + 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. + IMPORTANTE: Qualquer backup prévio que você tenha feito do seu arquivo wallet deve ser substituído pelo novo e encriptado arquivo wallet gerado. Por razões de segurança, qualquer backup do arquivo wallet não criptografado se tornará inútil assim que você começar a usar uma nova carteira criptografada. + + + + + Warning: The Caps Lock key is on! + Cuidado: A tecla Caps Lock está ligada! + + + + Wallet encrypted Carteira criptografada - - Bitcoin 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. - O Bitcoin irá fechar agora para finalizar o processo de encriptação. Lembre-se de que encriptar sua carteira não protege totalmente suas bitcoins de serem roubadas por malwares que tenham infectado o seu computador. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + O CasinoCoin irá fechar agora para finalizar o processo de encriptação. Lembre-se de que encriptar sua carteira não protege totalmente suas casinocoins de serem roubadas por malwares que tenham infectado o seu computador. - - - Warning: The Caps Lock key is on. - Aviso: A tecla Caps Lock está ligada. - - - - - - + + + + Wallet encryption failed A criptografia da carteira falhou - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. A criptografia da carteira falhou devido a um erro interno. Sua carteira não estava criptografada. - - + + The supplied passphrases do not match. A frase de segurança fornecida não confere. - + Wallet unlock failed A abertura da carteira falhou - - - + + + The passphrase entered for the wallet decryption was incorrect. A frase de segurança digitada para a descriptografia da carteira estava incorreta. - + Wallet decryption failed A descriptografia da carteira falhou - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. A frase de segurança da carteira foi alterada com êxito. BitcoinGUI - - Bitcoin Wallet - Carteira Bitcoin - - - + Sign &message... - + &Assinar Mensagem... - - Show/Hide &Bitcoin - Exibir/Ocultar &Bitcoin - - - + Synchronizing with network... Sincronizando com a rede... - + &Overview &Visão geral - + Show general overview of wallet Mostrar visão geral da carteira - + &Transactions &Transações - + Browse transaction history Navegar pelo histórico de transações - - &Address Book - &Catálogo de endereços - - - + Edit the list of stored addresses and labels Editar a lista de endereços e rótulos - - &Receive coins - &Receber moedas - - - + Show the list of addresses for receiving payments Mostrar a lista de endereços para receber pagamentos - - &Send coins - &Enviar moedas - - - - Prove you control an address - Prove que você controla um endereço - - - + E&xit - E&xit + S&air - + Quit application Sair da aplicação - - &About %1 - &About %1 + + Show information about CasinoCoin + Mostrar informação sobre CasinoCoin - - Show information about Bitcoin - Mostrar informação sobre Bitcoin - - - + About &Qt Sobre &Qt - + Show information about Qt Mostrar informações sobre o Qt - + &Options... &Opções... - + &Encrypt Wallet... - + &Criptografar Carteira... - + &Backup Wallet... - + &Backup Carteira... - + &Change Passphrase... - - - - - ~%n block(s) remaining - ~%n bloco restante~%n blocos restantes + &Mudar frase de segurança... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - + + Importing blocks from disk... + Importando blocos do disco... - - &Export... - &Exportar... + + Reindexing blocks on disk... + Reindexando blocos no disco... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Enviar moedas para um endereço casinocoin - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Modificar opções de configuração para casinocoin - - Show or hide the Bitcoin window - Exibir ou ocultar a janela Bitcoin - - - - Export the data in the current tab to a file - Exportar os dados na aba atual para um arquivo - - - - Encrypt or decrypt wallet - Criptografar ou decriptogravar carteira - - - + Backup wallet to another location Fazer cópia de segurança da carteira para uma outra localização - + Change the passphrase used for wallet encryption Mudar a frase de segurança utilizada na criptografia da carteira - + &Debug window - + Janela de &Depuração - + Open debugging and diagnostic console - + Abrir console de depuração e diagnóstico - + &Verify message... - + &Verificar mensagem... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Carteira + + + + &Send + &Enviar + + + + &Receive + &Receber + + + + &Addresses + &Endereços + + + + &About CasinoCoin + &Sobre o CasinoCoin + + + + &Show / Hide + &Exibir/Ocultar + + + + Show or hide the main Window + Mostrar ou esconder a Janela Principal. + + + + Encrypt the private keys that belong to your wallet + Criptografar as chaves privadas que pertencem à sua carteira + + + + Sign messages with your CasinoCoin addresses to prove you own them + Assine mensagems com seus endereços CasinoCoin para provar que você é dono deles + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verificar mensagens para se assegurar que elas foram assinadas pelo dono de Endereços CasinoCoin específicos + + + &File &Arquivo - + &Settings - E configurações + &Configurações - + &Help &Ajuda - + Tabs toolbar Barra de ferramentas - - Actions toolbar - Barra de ações - - - - + + [testnet] [testnet] - - - Bitcoin client - Cliente Bitcoin + + CasinoCoin client + Cliente CasinoCoin - - %n active connection(s) to Bitcoin network - %n conexão ativa na rede Bitcoin%n conexões ativas na rede Bitcoin + + %n active connection(s) to CasinoCoin network + %n conexão ativa na rede CasinoCoin%n conexões ativas na rede CasinoCoin - - Downloaded %1 blocks of transaction history. - Carregados %1 blocos do histórico de transações. - - - - %n second(s) ago - %n segundo atrás%n segundos atrás - - - - %n minute(s) ago - %n minutos atrás%n minutos atrás - - - - %n hour(s) ago - %n hora atrás%n horas atrás - - - - %n day(s) ago - %n dia atrás%n dias atrás + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + Processado %1 de %2 blocos (estimado) de histórico de transações. + + + + Processed %1 blocks of transaction history. + Processado %1 blocos do histórico de transações. + + + + %n hour(s) + %n hora%n horas + + + + %n day(s) + %n dia%n dias + + + + %n week(s) + %n semana%n semanas + + + + %1 behind + %1 atrás + + + + Last received block was generated %1 ago. + Último bloco recebido foi gerado %1 atrás. + + + + Transactions after this will not yet be visible. + Transações após isso ainda não estão visíveis. + + + + Error + Erro + + + + Warning + Cuidado + + + + Information + Informação + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + A transação está acima do tamanho limite. Você ainda enviar ela com uma taxa de %1, que vai para os nós processam sua transação e ajuda a manter a rede. Você quer pagar a taxa? + + + Up to date Atualizado - + Catching up... Recuperando o atraso ... - - Last received block was generated %1. - Last received block was generated %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - - - + Confirm transaction fee - + Confirmar taxa de transação - + Sent transaction - Sent transaction + Transação enviada - + Incoming transaction - Incoming transaction + Transação recebida - + Date: %1 Amount: %2 Type: %3 @@ -580,539 +647,485 @@ Tipo: %3 Endereço: %4 - + + + URI handling + Manipulação de URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI não pode ser decodificado! Isso pode ter sido causado por um endereço CasinoCoin inválido ou por parâmetros URI malformados. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Carteira está <b>criptografada</b> e atualmente <b>desbloqueada</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> - Wallet is <b>encrypted</b> and currently <b>locked</b> + Carteira está <b>criptografada</b> e atualmente <b>bloqueada</b> - - Backup Wallet - Fazer cópia de segurança da Carteira - - - - Wallet Data (*.dat) - Dados da Carteira (*.dat) - - - - Backup Failed - Cópia de segurança Falhou - - - - There was an error trying to save the wallet data to the new location. - Houve um erro ao tentar salvar os dados da carteira para uma nova localização. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Um erro fatal ocorreu. CasinoCoin não pode continuar em segurança e irá fechar. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Display - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Choose the default subdivision unit to show in the interface, and when sending coins - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Alerta da Rede EditAddressDialog - + Edit Address - Edit Address + Editar Endereço - + &Label - &Label + &Etiqueta - + The label associated with this address book entry - The label associated with this address book entry + A etiqueta associada a esse endereço do catálogo - + &Address - &Address + &Endereço - + The address associated with this address book entry. This can only be modified for sending addresses. - The address associated with this address book entry. This can only be modified for sending addresses. + O endereço associado à essa entrada do seu catálogo de endereços. Isso só pode ser modificado para endereço de envio. - + New receiving address - New receiving address + Novo endereço de recebimento - + New sending address - New sending address + Novo endereço de envio - + Edit receiving address - Edit receiving address + Editar endereço de recebimento - + Edit sending address - Edit sending address + Editar endereço de envio - + The entered address "%1" is already in the address book. - The entered address "%1" is already in the address book. + O endereço digitado "%1" já se encontra no catálogo de endereços. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + O endereço digitado "%1" não é um endereço CasinoCoin válido. - + Could not unlock wallet. - Could not unlock wallet. + Não foi possível destravar a carteira. - + New key generation failed. - New key generation failed. + A geração de nova chave falhou. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versão - + Usage: - Usage: + Uso: - - options - + + command-line options + opções da linha de comando - + UI options - + opções da UI - + Set language, for example "de_DE" (default: system locale) - + Escolher língua, por exemplo "de_DE" (padrão: localização do sistema) - + Start minimized - Start minimized - + Inicializar minimizado - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - Pay transaction &fee - - - - Main - Principal - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Taxa opcional de transações por kB que ajuda a garantir que suas transações serão processadas rapidamente. A maior parte das transações é de 1 kB. Taxa de 0.01 recomendada. - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Você pode assinar mensagens com seus endereços para provar que você é o dono deles. Seja cuidadoso para não assinar algo vago, pois ataques de pishing podem tentar te enganar para dar sua assinatura de identidade para eles. Apenas assine afirmações completamente detalhadas com as quais você concorda. - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - O endereço a ser utilizado para assinar a mensagem (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Escolher endereço - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Paste address from clipboard - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Entre a mensagem que você quer assinar aqui - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Clique "Assinar Mensagem" para conseguir a assinatura - - - - Sign a message to prove you own this address - Assine uma mensagem para provar que você é o dono desse endereço - - - - &Sign Message - &Assinar Mensagem - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Erro ao assinar - - - - %1 is not a valid address. - %1 não é um endereço válido. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Chave privada para %1 não está disponível. - - - - Sign failed - Assinatura falhou - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - Map port using &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - &Connect through SOCKS4 proxy: - &Connect through SOCKS4 proxy: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - IP address of the proxy (e.g. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Port of the proxy (e.g. 1234) + Mostrar tela inicial ao ligar (padrão: 1) OptionsDialog - + Options - Options + Opções + + + + &Main + Principal + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + Pagar taxa de &transação + + + + Automatically start CasinoCoin after logging in to the system. + Iniciar CasinoCoin automaticamente após se logar no sistema. + + + + &Start CasinoCoin on system login + Iniciar CasinoCoin no login do sistema + + + + Reset all client options to default. + Redefinir todas as opções do cliente para opções padrão. + + + + &Reset Options + &Redefinir opções + + + + &Network + Rede + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Abrir as portas do cliente CasinoCoin automaticamente no roteador. Isto só funcionará se seu roteador suportar UPnP e esta função estiver habilitada. + + + + Map port using &UPnP + Mapear porta usando &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Conectar à rede CasinoCoin através de um proxy SOCKS (ex. quando estiver usando através do Tor) + + + + &Connect through SOCKS proxy: + &Conectar através de um proxy SOCKS: + + + + Proxy &IP: + &IP do proxy: + + + + IP address of the proxy (e.g. 127.0.0.1) + Endereço &IP do proxy (ex. 127.0.0.1) + + + + &Port: + &Porta: + + + + Port of the proxy (e.g. 9050) + Porta do serviço de proxy (ex. 9050) + + + + SOCKS &Version: + &Versão do SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Versão do proxy SOCKS (ex. 5) + + + + &Window + &Janela + + + + Show only a tray icon after minimizing the window. + Mostrar apenas um ícone na bandeja ao minimizar a janela. + + + + &Minimize to the tray instead of the taskbar + &Minimizar para a bandeja em vez da barra de tarefas. + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimizar em vez de sair do aplicativo quando a janela for fechada. Quando esta opção é escolhida, o aplicativo só será fechado selecionando Sair no menu Arquivo. + + + + M&inimize on close + M&inimizar ao sair + + + + &Display + &Mostrar + + + + User Interface &language: + &Língua da interface com usuário: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + A língua da interface com usuário pode ser escolhida aqui. Esta configuração só surtirá efeito após reiniciar o CasinoCoin. + + + + &Unit to show amounts in: + &Unidade usada para mostrar quantidades: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Escolha a unidade padrão de subdivisão para interface mostrar quando enviar casinocoins. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Mostrar ou não endereços CasinoCoin na lista de transações. + + + + &Display addresses in transaction list + Mostrar en&dereços na lista de transações + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + &Apply + &Aplicar + + + + default + padrão + + + + Confirm options reset + Confirmar redefinição de opções + + + + Some settings may require a client restart to take effect. + Algumas configurações requerem reinicialização para surtirem efeito. + + + + Do you want to proceed? + Você quer continuar? + + + + + Warning + Cuidado + + + + + This setting will take effect after restarting CasinoCoin. + Esta configuração surtirá efeito após reinicializar o aplicativo CasinoCoin + + + + The supplied proxy address is invalid. + O endereço proxy fornecido é inválido. OverviewPage - + Form - Form + Formulário - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + A informação mostrada pode estar desatualizada. Sua carteira sincroniza automaticamente com a rede CasinoCoin depois que a conexão é estabelecida, mas este processo pode não estar completo ainda. - + Balance: - Balance: + Saldo: - - Number of transactions: - Number of transactions: - - - + Unconfirmed: - Unconfirmed: + Não confirmadas: - + Wallet - + Carteira - + + Immature: + Imaturo: + + + + Mined balance that has not yet matured + Saldo minerado que ainda não maturou + + + <b>Recent transactions</b> - <b>Recent transactions</b> + <b>Transações recentes</b> - + Your current balance - Your current balance + Seu saldo atual - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + Total de transações ainda não confirmadas, e que ainda não contam no saldo atual - - Total number of transactions in wallet - Total number of transactions in wallet - - - - + + out of sync - + fora de sincronia + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Não foi possível iniciar casinocoin: manipulador clique-para-pagar QRCodeDialog - + QR Code Dialog - + Janela do código QR - - QR Code - Código QR - - - + Request Payment Requisitar Pagamento - + Amount: Quantia: - - BTC - BTC - - - + Label: Etiqueta: - + Message: - Message: + Mensagem: - + &Save As... &Salvar como... - + Error encoding URI into QR Code. - + Erro ao codigicar o URI em código QR - + + The entered amount is invalid, please check. + A quantidade digitada é inválida, favor verificar. + + + Resulting URI too long, try to reduce the text for label / message. URI resultante muito longa. Tente reduzir o texto do rótulo ou da mensagem. - + Save QR Code - + Salvar código QR - + PNG Images (*.png) Imagens PNG (*.png) @@ -1120,1418 +1133,1805 @@ Endereço: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Nome do cliente - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + Versão do cliente - + &Information - + &Informação - - Client - + + Using OpenSSL version + Usando OpenSSL versão - + Startup time - + Horário de inicialização - + Network - + Rede - + Number of connections - + Número de conexões - + On testnet - + Na rede de teste - + Block chain - + Corrente de blocos - + Current number of blocks - + Quantidade atual de blocos - + Estimated total blocks - + Total estimado de blocos - + Last block time - + Horário do último bloco - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Abrir - + + Command-line options + Opções da linha de comando + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Mostrar mensagem de ajuda do CasinoCoin-Qt para obter uma lista com possíveis opções da linha de comando do CasinoCoin. + + + + &Show + &Mostrar + + + &Console - + &Console - + Build date - + Data do 'build' - + + CasinoCoin - Debug window + CasinoCoin - Janela de Depuração + + + + CasinoCoin Core + Núcleo CasinoCoin + + + + Debug log file + Arquivo de log de Depuração + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Abrir o arquivo de log de depuração do CasinoCoin do diretório atual de dados. Isso pode levar alguns segundos para arquivos de log grandes. + + + Clear console - + Limpar console - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Bem-vindo ao console CasinoCoin RPC. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Use as setas para cima e para baixo para navegar pelo histórico, e <b>Ctrl-L</b> para limpar a tela. - + Type <b>help</b> for an overview of available commands. - + Digite <b>help</b> para uma visão geral dos comandos disponíveis. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Send Coins + Enviar dinheiro - + Send to multiple recipients at once - Send to multiple recipients at once + Enviar para vários destinatários de uma só vez - - &Add Recipient - + + Add &Recipient + Adicionar destinatário - + Remove all transaction fields Remover todos os campos da transação - + Clear &All - + Limpar Tudo - + Balance: - Balance: + Saldo: - + 123.456 BTC 123.456 BTC - + Confirm the send action - Confirm the send action + Confirmar o envio - - &Send - &Send + + S&end + Enviar - + <b>%1</b> to %2 (%3) - <b>%1</b> to %2 (%3) + <b>%1</b> para %2 (%3) - + Confirm send coins - Confirm send coins + Confirmar envio de dinheiro - + Are you sure you want to send %1? - Are you sure you want to send %1? + Você tem certeza que deseja enviar %1? - + and - and + e - - The recepient address is not valid, please recheck. - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. + O endereço do destinatário não é válido, favor verificar. - + The amount to pay must be larger than 0. - The amount to pay must be larger than 0. + A quantidade a ser paga precisa ser maior que 0. - + The amount exceeds your balance. - + A quantidade excede seu saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + O total excede seu saldo quando uma taxa de transação de %1 é incluída. - + Duplicate address found, can only send to each address once per send operation. - + Endereço duplicado: pode-se enviar para cada endereço apenas uma vez por transação. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Erro: Criação da transação falhou! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Erro: A transação foi rejeitada. Isso pode acontecer se alguns dos casinocoins de sua carteira já haviam sido gastos, por exemplo se você usou uma cópia do arquivo wallet.dat e alguns casinocoins foram gastos na cópia mas não foram marcados como gastos aqui. SendCoinsEntry - + Form - Form + Formulário - + A&mount: - A&mount: + Q&uantidade: - + Pay &To: - Pay &To: + Pagar &Para: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + O endereço para onde enviar o pagamento (ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book - Enter a label for this address to add it to your address book + Digite uma etiqueta para este endereço para adicioná-lo ao catálogo de endereços - + &Label: - &Label: + &Etiqueta: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book - Choose address from address book + Escolha um endereço do seu catálogo - + Alt+A Alt+A - + Paste address from clipboard - Paste address from clipboard + Colar o endereço da área de transferência - + Alt+P Alt+P - + Remove this recipient - Remove this recipient + Remover este destinatário - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Digite um endereço CasinoCoin (exemplo: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Assinaturas - Assinar / Verificar uma mensagem + + + + &Sign Message + &Assinar Mensagem + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Você pode assinar mensagens com seus endereços para provar que você é o dono deles. Seja cuidadoso para não assinar algo vago, pois ataques de pishing podem tentar te enganar para dar sua assinatura de identidade para eles. Apenas assine afirmações completamente detalhadas com as quais você concorda. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Endereço a ser usado para assinar a mensagem (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Escolha um endereço do catálogo + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Colar o endereço da área de transferência + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Entre a mensagem que você quer assinar aqui + + + + Signature + Assinatura + + + + Copy the current signature to the system clipboard + Copiar a assinatura para a área de transferência do sistema + + + + Sign the message to prove you own this CasinoCoin address + Assinar mensagem para provar que você é dono deste endereço CasinoCoin + + + + Sign &Message + Assinar &Mensagem + + + + Reset all sign message fields + Limpar todos os campos de assinatura da mensagem + + + + + Clear &All + Limpar Tudo + + + + &Verify Message + &Verificar Mensagem + + + + Enter the signing 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. + Forneça o endereço da assinatura, a mensagem (se assegure que você copiou quebras de linha, espaços, tabs, etc. exatamente) e a assinatura abaixo para verificar a mensagem. Cuidado para não ler mais na assinatura do que está escrito na mensagem propriamente, para evitar ser vítima de uma ataque do tipo "man-in-the-middle". + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + O endereço usado para assinar a mensagem (ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verificar mensagem para se assegurar que ela foi assinada pelo dono de um endereço CasinoCoin específico. + + + + Verify &Message + Verificar %Mensagem + + + + Reset all verify message fields + Limpar todos os campos de assinatura da mensagem + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Digite um endereço CasinoCoin (exemplo: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Clique em "Assinar Mensagem" para gerar a assinatura + + + + Enter CasinoCoin signature + Entre com a assinatura CasinoCoin + + + + + The entered address is invalid. + O endereço fornecido é inválido. + + + + + + + Please check the address and try again. + Por favor, verifique o endereço e tente novamente. + + + + + The entered address does not refer to a key. + O endereço fornecido não se refere a uma chave. + + + + Wallet unlock was cancelled. + Destravamento da Carteira foi cancelado. + + + + Private key for the entered address is not available. + A chave privada para o endereço fornecido não está disponível. + + + + Message signing failed. + Assinatura da mensagem falhou. + + + + Message signed. + Mensagem assinada. + + + + The signature could not be decoded. + A assinatura não pode ser decodificada. + + + + + Please check the signature and try again. + Por favor, verifique a assinatura e tente novamente. + + + + The signature did not match the message digest. + A assinatura não corresponde ao "resumo da mensagem". + + + + Message verification failed. + Verificação da mensagem falhou. + + + + Message verified. + Mensagem verificada. + + + + SplashScreen + + + The CasinoCoin developers + Desenvolvedores do CasinoCoin + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Open for %1 blocks - - - + Open until %1 - Open until %1 + Aberto até %1 - - %1/offline? - %1/offline? + + %1/offline + %1/offline - + %1/unconfirmed - %1/unconfirmed + %1/não confirmadas - + %1 confirmations - %1 confirmations + %1 confirmações - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , difundir atráves de %n nó, difundir atráves de %n nós - + + Date + Data + + + + Source + Fonte + + + + Generated + Gerados + + + + + From + De + + + + + + To + Para + + + + + own address + seu próprio endereço + + + + label + etiqueta + + + + + + + + Credit + Crédito + + + + matures in %n more block(s) + matura em mais %n blocomatura em mais %n blocos + + + + not accepted + não aceito + + + + + + + Debit + Débito + + + + Transaction fee + Taxa de transação + + + + Net amount + Valor líquido + + + + Message + Mensagem + + + + Comment + Comentário + + + + Transaction ID + ID da transação + + + + Generated coins must mature 120 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. + CasinoCoins gerados precisam maturar por 120 blocos antes de serem gastos. Quando você gera este bloco, ele é difundido na rede para ser adicionado ao blockchain. Se ele falhar ao ser acrescentado no blockchain, seu estado mudará para "não aceito" e não poderá ser gasto. Isso pode ocasionamente acontecer se outro nó gerou um bloco poucos segundos antes do seu. + + + + Debug information + Informação de depuração + + + + Transaction + Transação + + + + Inputs + Entradas + + + + Amount + Quantidade + + + + true + verdadeiro + + + + false + falso + + + , has not been successfully broadcast yet - , has not been successfully broadcast yet + , ainda não foi propagada na rede com sucesso. + + + + Open for %n more block(s) + Abrir para mais %n blocoAbrir para mais %n blocos - - , broadcast through %1 node - , broadcast through %1 node - - - - , broadcast through %1 nodes - , broadcast through %1 nodes - - - - <b>Date:</b> - <b>Date:</b> - - - - <b>Source:</b> Generated<br> - <b>Source:</b> Generated<br> - - - - - <b>From:</b> - <b>From:</b> - - - + unknown - unknown - - - - - - <b>To:</b> - <b>To:</b> - - - - (yours, label: - (yours, label: - - - - (yours) - (yours) - - - - - - - <b>Credit:</b> - <b>Credit:</b> - - - - (%1 matures in %2 more blocks) - (%1 matures in %2 more blocks) - - - - (not accepted) - (not accepted) - - - - - - <b>Debit:</b> - <b>Debit:</b> - - - - <b>Transaction fee:</b> - <b>Transaction fee:</b> - - - - <b>Net amount:</b> - <b>Net amount:</b> - - - - Message: - Message: - - - - Comment: - Comment: - - - - Transaction ID: - ID da Transação: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + desconhecido TransactionDescDialog - + Transaction details - Transaction details + Detalhes da transação - + This pane shows a detailed description of the transaction - This pane shows a detailed description of the transaction + Este painel mostra uma descrição detalhada da transação TransactionTableModel - + Date - Date + Data - + Type - Type + Tipo - + Address - Address + Endereço - + Amount - Amount + Quantidade - - Open for %n block(s) - Open for %n blockOpen for %n blocks + + Open for %n more block(s) + Abrir para mais %n blocoAbrir para mais %n blocos - + Open until %1 - Open until %1 + Aberto até %1 - + Offline (%1 confirmations) - Offline (%1 confirmations) + Offline (%1 confirmações) - + Unconfirmed (%1 of %2 confirmations) - Unconfirmed (%1 of %2 confirmations) + Não confirmado (%1 of %2 confirmações) - + Confirmed (%1 confirmations) - Confirmed (%1 confirmations) + Confirmado (%1 confirmações) - - Mined balance will be available in %n more blocks - Mined balance will be available in %n more blockMined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) + Saldo minerado vai estar disponível quando ele maturar em mais %n blocoSaldo minerado vai estar disponível quando ele maturar em mais %n blocos - + This block was not received by any other nodes and will probably not be accepted! - This block was not received by any other nodes and will probably not be accepted! + Este bloco não foi recebido por nenhum outro participante da rede e provavelmente não será aceito! - + Generated but not accepted - Generated but not accepted + Gerado mas não aceito - + Received with - Received with + Recebido por - + Received from Recebido de - + Sent to - Sent to + Enviado para - + Payment to yourself - Payment to yourself + Pagamento para você mesmo - + Mined - Mined + Minerado - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. - Transaction status. Hover over this field to show number of confirmations. + Status da transação. Passe o mouse sobre este campo para mostrar o número de confirmações. - + Date and time that the transaction was received. - Date and time that the transaction was received. + Data e hora em que a transação foi recebida. - + Type of transaction. - Type of transaction. + Tipo de transação. - + Destination address of transaction. - Destination address of transaction. + Endereço de destino da transação. - + Amount removed from or added to balance. - Amount removed from or added to balance. + Quantidade debitada ou creditada ao saldo. TransactionView - - + + All - All + Todos - + Today - Today + Hoje - + This week - This week + Esta semana - + This month - This month + Este mês - + Last month - Last month + Mês passado - + This year - This year + Este ano - + Range... - Range... + Intervalo... - + Received with - Received with + Recebido por - + Sent to - Sent to + Enviado para - + To yourself - To yourself + Para você mesmo - + Mined - Mined + Minerado - + Other - Other + Outro - + Enter address or label to search - Enter address or label to search + Procure um endereço ou etiqueta - + Min amount - Min amount + Quantidade mínima - + Copy address - Copy address + Copiar endereço - + Copy label - Copy label + Copiar etiqueta - + Copy amount Copiar quantia - + + Copy transaction ID + Copiar ID da transação + + + Edit label - Edit label + Editar etiqueta - + Show transaction details - + Mostrar detalhes da transação - + Export Transaction Data - Export Transaction Data + Exportar Dados das Transações - + Comma separated file (*.csv) - Comma separated file (*.csv) + Arquivo separado por vírgulas (*. csv) - + Confirmed - Confirmed + Confirmado - + Date - Date + Data - + Type - Type + Tipo - + Label - Label + Etiqueta - + Address - Address + Endereço - + Amount - Amount + Quantidade - + ID ID - + Error exporting - Error exporting + Erro ao exportar - + Could not write to file %1. - Could not write to file %1. + Não foi possível gravar no arquivo %1. - + Range: - Range: + Intervalo: - + to - to - - - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copie o endereço selecionado para a área de transferência do sistema - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - + para WalletModel - - Sending... - Sending... + + Send Coins + Send Coins - WindowOptionsPage + WalletView - - Window - + + &Export + &Exportar - - &Minimize to the tray instead of the taskbar - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file + Exportar os dados na aba atual para um arquivo - - Show only a tray icon after minimizing the window - Show only a tray icon after minimizing the window + + Backup Wallet + Fazer cópia de segurança da Carteira - - M&inimize on close - + + Wallet Data (*.dat) + Dados da Carteira (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + Backup Failed + Cópia de segurança Falhou + + + + There was an error trying to save the wallet data to the new location. + Houve um erro ao tentar salvar os dados da carteira para uma nova localização. + + + + Backup Successful + Backup feito com sucesso + + + + The wallet data was successfully saved to the new location. + Os dados da carteira foram salvos com sucesso na nova localização bitcoin-core - - Bitcoin version - Bitcoin version + + CasinoCoin version + Versão do CasinoCoin - + Usage: - Usage: + Uso: - - Send command to -server or bitcoind - Send command to -server or bitcoind - + + Send command to -server or casinocoind + Enviar comando para -server ou casinocoind - + List commands - List commands - + Lista de comandos - + Get help for a command - Get help for a command - + Obtenha ajuda sobre um comando - + Options: - Options: - + Opções: - - Specify configuration file (default: bitcoin.conf) - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Especifique um arquivo de configurações (padrão: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Specify pid file (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + Especifique um arquivo de pid (padrão: casinocoind.pid) - - Generate coins - Generate coins - - - - - Don't generate coins - Don't generate coins - - - - + Specify data directory - Specify data directory - + Especificar diretório de dados - + Set database cache size in megabytes (default: 25) Definir o tamanho do cache do banco de dados em megabytes (padrão: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Procurar por conexões em <port> (padrão: 47950 ou testnet:17950) - - Specify connection timeout (in milliseconds) - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Procurar por conexões em <port> (padrão: 8333 ou testnet:18333) - - - + Maintain at most <n> connections to peers (default: 125) Manter no máximo <n> conexões aos peers (padrão: 125) - - Connect only to the specified node - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Conectar a um nó para receber endereços de participantes, e desconectar. - + Specify your own public address - + Especificar seu próprio endereço público - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Limite para desconectar peers mal comportados (padrão: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Número de segundos para impedir que peers mal comportados reconectem (padrão: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Buffer máximo a ser recebido por conexão, <n>*1000 bytes (padrão: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Um erro ocorreu ao configurar a porta RPC %u para escuta em IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Buffer de envio máximo por conexão, <n>*1000 bytes (padrão: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Escutar conexões JSON-RPC na porta <porta> (padrão: 47970 ou testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) + + Accept command line and JSON-RPC commands + Aceitar linha de comando e comandos JSON-RPC + + + + Run in the background as a daemon and accept commands + Rodar em segundo plano como serviço e aceitar comandos + + + + Use the test network + Usar rede de teste + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Aceitar conexões externas (padrão: 1 se opções -proxy ou -connect não estiverem presentes) + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, você deve especificar uma senha rpcpassword no arquivo de configuração:⏎ +%s⏎ +É recomendado que você use a seguinte senha aleatória:⏎ +rpcuser=casinocoinrpc⏎ +rpcpassword=%s⏎ +(você não precisa lembrar esta senha)⏎ +O nome de usuário e a senha NÃO PODEM ser os mesmos.⏎ +Se o arquivo não existir, crie um com permissão de leitura apenas para o dono.⏎ +É recomendado também definir um alertnotify para que você seja notificado de problemas;⏎ +por exemplo: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com⏎ + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Um erro ocorreu ao configurar a porta RPC %u para escuta em IPv6, voltando ao IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Vincular ao endereço fornecido e sempre escutar nele. Use a notação [host]:port para IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Não foi possível obter exclusividade de escrita no endereço %s. O CasinoCoin provavelmente já está rodando. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Erro: A transação foi rejeitada. Isso pode acontecer se alguns dos casinocoins de sua carteira já haviam sido gastos, por exemplo se você usou uma cópia do arquivo wallet.dat e alguns casinocoins foram gastos na cópia mas não foram marcados como gastos aqui. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Erro: Esta transação requer uma taxa de transação de pelo menos %s, por causa sua quantidade, complexidade ou uso de dinheiro recebido recentemente. + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Executar comando quando um alerta relevante for recebido (%s no comando será substituído pela mensagem) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Executar comando quando uma transação da carteira mudar (%s no comando será substituído por TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Determinar tamanho máximo de transações de alta-prioridade/baixa-taxa em bytes (padrão: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + 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. + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Cuidado: valor de -paytxfee escolhido é muito alto! Este é o valor da taxa de transação que você irá pagar se enviar a transação. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Cuidado: Transações mostradas podem não estar corretas! Você pode precisar atualizar, ou outros nós podem precisar atualizar o cliente. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Cuidado: Por favor, verifique que a data e hora do seu computador estão corretas! If o seu relógio estiver errado, o CasinoCoin não irá funcionar corretamente. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Cuidado: erro ao ler arquivo wallet.dat! Todas as chaves foram lidas corretamente, mas dados transações e do catálogo de endereços podem estar faltando ou estar incorretas. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Aviso: wallet.dat corrompido, dados recuperados! Arquivo wallet.dat original salvo como wallet.{timestamp}.bak em %s; se seu saldo ou transações estiverem incorretos, você deve restauras o backup. + + + + Attempt to recover private keys from a corrupt wallet.dat + Tentar recuperar chaves privadas de um arquivo wallet.dat corrompido + + + + Block creation options: + Opções de criação de blocos: + + + + Connect only to the specified node(s) + Conectar apenas a nó(s) específico(s) + + + + Corrupted block database detected + Detectado Banco de dados de blocos corrompido + + + + Discover own IP address (default: 1 when listening and no -externalip) + Descobrir os próprios endereços IP (padrão: 1 quando no modo listening e opção -externalip não estiver presente) + + + + Do you want to rebuild the block database now? + Você quer reconstruir o banco de dados de blocos agora? + + + + Error initializing block database + Erro ao inicializar banco de dados de blocos + + + + Error initializing wallet database environment %s! + Erro ao inicializar ambiente de banco de dados de carteira %s! + + + + Error loading block database + Erro ao carregar banco de dados de blocos + + + + Error opening block database + Erro ao abrir banco de dados de blocos + + + + Error: Disk space is low! + Erro: Espaço em disco insuficiente! + + + + Error: Wallet locked, unable to create transaction! + Erro: Carteira travada, impossível criar transação! + + + + Error: system error: + Erro: erro de sistema + + + + Failed to listen on any port. Use -listen=0 if you want this. + Falha ao escutar em qualquer porta. Use -listen=0 se você quiser isso. + + + + Failed to read block info + Falha ao ler informação de bloco + + + + Failed to read block + Falha ao ler bloco + + + + Failed to sync block index + Falha ao sincronizar índice de blocos + + + + Failed to write block index + Falha ao escrever índice de blocos + + + + Failed to write block info + Falha ao escrever informações de bloco + + + + Failed to write block + Falha ao escrever bloco + + + + Failed to write file info + Falha ao escrever informções de arquivo + + + + Failed to write to coin database + Falha ao escrever banco de dados de moedas + + + + Failed to write transaction index + Falha ao escrever índice de transações + + + + Failed to write undo data + Falha ao escrever dados para desfazer ações + + + + Find peers using DNS lookup (default: 1 unless -connect) + Procurar pares usando consulta de DNS (padrão: 1 a menos que a opção -connect esteja presente) + + + + Generate coins (default: 0) - - Accept command line and JSON-RPC commands - Accept command line and JSON-RPC commands - + + How many blocks to check at startup (default: 288, 0 = all) + Quantos blocos checar ao inicializar (padrão: 288, 0 = todos) - - Run in the background as a daemon and accept commands - Run in the background as a daemon and accept commands - + + How thorough the block verification is (0-4, default: 3) + Quão minuciosa é a verificação dos blocos (0-4, padrão: 3) - - Use the test network - Use the test network - + + Not enough file descriptors available. + - - Output extra debugging information - Produzir informação extra para debugging + + Rebuild block chain index from current blk000??.dat files + Reconstruir índice de blockchain a partir dos arquivos atuais blk000??.dat - + + Set the number of threads to service RPC calls (default: 4) + Defina o número de threads de script de verificação. (Padrão: 4) + + + + Verifying blocks... + Verificando blocos... + + + + Verifying wallet... + Verificando carteira... + + + + Imports blocks from external blk000??.dat file + Importar blocos de um arquivo externo blk000??.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Informação + + + + Invalid -tor address: '%s' + Endereço -tor inválido: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + Manter índice completo de transações (padrão: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Buffer máximo de recebimento por conexão, <n>*1000 bytes (padrão: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Buffer máximo de envio por conexão, <n>*1000 bytes (padrão: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Apenas aceitar cadeia de blocos correspondente a marcas de verificação internas (padrão: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Apenas conectar em nós na rede <net> (IPv4, IPv6, ou Tor) + + + + Output extra debugging information. Implies all other -debug* options + Mostrar informações extras de depuração. Implica em outras opções -debug* + + + + Output extra network debugging information + Mostrar informações extras de depuração da rede + + + Prepend debug output with timestamp Pré anexar a saída de debug com estampa de tempo - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opções SSL: (veja a Wiki do CasinoCoin para instruções de configuração SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Escolher versão do proxy socks a ser usada (4-5, padrão: 5) + + + Send trace/debug info to console instead of debug.log file Mandar informação de trace/debug para o console em vez de para o arquivo debug.log - + Send trace/debug info to debugger Mandar informação de trace/debug para o debugger - - Username for JSON-RPC connections - Username for JSON-RPC connections - + + Set maximum block size in bytes (default: 250000) + Determinar tamanho máximo de bloco em bytes (padrão: 250000) - - Password for JSON-RPC connections - Password for JSON-RPC connections - + + Set minimum block size in bytes (default: 0) + Determinar tamanho mínimo de bloco em bytes (padrão: 0) - - Listen for JSON-RPC connections on <port> (default: 8332) - Listen for JSON-RPC connections on <port> (default: 8332) - + + Shrink debug.log file on client startup (default: 1 when no -debug) + Encolher arquivo debug.log ao iniciar o cliente (padrão 1 se opção -debug não estiver presente) - - Allow JSON-RPC connections from specified IP address - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) + + Signing transaction failed - + + Specify connection timeout in milliseconds (default: 5000) + Especifique o tempo limite (timeout) da conexão em milissegundos (padrão: 5000) + + + + System error: + Erro de sistema: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Usar UPnP para mapear porta de escuta (padrão: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Usar UPnP para mapear porta de escuta (padrão: 1 quando estiver escutando) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Usar proxy para alcançar serviços escondidos (padrão: mesmo que -proxy) + + + + Username for JSON-RPC connections + Nome de usuário para conexões JSON-RPC + + + + Warning + Cuidado + + + + Warning: This version is obsolete, upgrade required! + Cuidado: Esta versão está obsoleta, atualização exigida! + + + + You need to rebuild the databases using -reindex to change -txindex + Você precisa reconstruir os bancos de dados usando -reindex para mudar -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat corrompido, recuperação falhou + + + + Password for JSON-RPC connections + Senha para conexões JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Permitir conexões JSON-RPC de endereços IP específicos + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Enviar comando para nó rodando em <ip> (pardão: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Executar comando quando o melhor bloco mudar (%s no comando será substituído pelo hash do bloco) + + + Upgrade wallet to latest format Atualizar carteira para o formato mais recente - + Set key pool size to <n> (default: 100) - Set key pool size to <n> (default: 100) - + Determinar tamanho do pool de endereços para <n> (padrão: 100) - + Rescan the block chain for missing wallet transactions - Rescan the block chain for missing wallet transactions - + Re-escanear blocos procurando por transações perdidas da carteira - - How many blocks to check at startup (default: 2500, 0 = all) - Quantos blocos verificar ao iniciar (padrão: 2500, 0 = todos) - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - + Use OpenSSL (https) for JSON-RPC connections - Use OpenSSL (https) for JSON-RPC connections - + Usar OpenSSL (https) para conexões JSON-RPC - + Server certificate file (default: server.cert) - Server certificate file (default: server.cert) - + Arquivo de certificado do servidor (padrão: server.cert) - + Server private key (default: server.pem) - Server private key (default: server.pem) - + Chave privada do servidor (padrão: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + Algoritmos de criptografia aceitos (padrão: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message - This help message - + Esta mensagem de ajuda - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Impossível vincular a %s neste computador (bind retornou erro %d, %s) - + Connect through socks proxy - + Conectar através de um proxy socks - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Permitir consultas DNS para -addnode, -seednode e -connect - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... - Loading addresses... + Carregando endereços... - - Error loading blkindex.dat - Erro ao carregar blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Erro ao carregar wallet.dat: Carteira corrompida - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Erro ao carregar wallet.dat: Carteira requer uma versão mais nova do Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Erro ao carregar wallet.dat: Carteira requer uma versão mais nova do CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - A Carteira precisou ser reescrita: reinicie o Bitcoin para completar + + Wallet needed to be rewritten: restart CasinoCoin to complete + A Carteira precisou ser reescrita: reinicie o CasinoCoin para completar - + Error loading wallet.dat Erro ao carregar wallet.dat - + Invalid -proxy address: '%s' - + Endereço -proxy inválido: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Rede desconhecida especificada em -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Versão desconhecida do proxy -socks requisitada: %i - + Cannot resolve -bind address: '%s' - + Impossível encontrar o endereço -bind: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Impossível encontrar endereço -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Quantidade inválida para -paytxfee=<quantidade>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Erro: Carteira bloqueada, incapaz de criar transação - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Error: Transaction creation failed - - - - Sending... - Enviando... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - + Invalid amount - + Quantidade inválida - + Insufficient funds - Insufficient funds + Saldo insuficiente - + Loading block index... - Loading block index... + Carregando índice de blocos... - + Add a node to connect to and attempt to keep the connection open - + Adicionar um nó com o qual se conectar e tentar manter a conexão ativa - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Impossível vincular a %s neste computador. O CasinoCoin provavelmente já está rodando. - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - + Fee per KB to add to transactions you send - Fee per KB to add to transactions you send + Taxa por KB a ser acrescida nas transações que você enviar - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... - Loading wallet... + Carregando carteira... - + Cannot downgrade wallet - + Não é possível fazer downgrade da carteira - - Cannot initialize keypool - - - - + Cannot write default address - + Não foi possível escrever no endereço padrão - + Rescanning... - Rescanning... + Re-escaneando... - + Done loading - Done loading + Carregamento terminado - + To use the %s option - + Para usar a opção %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - - - - + Error - + Erro - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. + Você precisa especificar rpcpassword=<senha> no arquivo de configurações:⏎ +%s⏎ +Se o arquivo não existir, crie um com permissão de leitura apenas pelo dono \ No newline at end of file diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index bd7f74b..db18ef0 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -3,140 +3,178 @@ AboutDialog - - About Bitcoin - Sobre o Bitcoin + + About CasinoCoin + Sobre CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versão + + <b>CasinoCoin</b> version + Versão do <b>CasinoCoin</b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Todos os direitos reservados © 2009-2012 Programadores Bitcoin - + Este é um programa experimental. -Distribuído sobre uma licença de software MIT/X11, por favor verifique o ficheiro anexo license.txt ou http://www.opensource.org/licenses/mit-license.php. +Distribuído sob uma licença de software MIT/X11, por favor verifique o ficheiro anexo license.txt ou http://www.opensource.org/licenses/mit-license.php. Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no OpenSSL Toolkit (http://www.openssl.org/), software criptográfico escrito por Eric Young (eay@cryptsoft.com) e software UPnP escrito por Thomas Bernard. + + + Copyright + Copyright + + + + The CasinoCoin developers + Os programadores CasinoCoin + AddressBookPage - + Address Book Livro de endereços - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Estes são os seus endereços Bitcoin para receber pagamentos. Poderá enviar um endereço diferente para cada remetente para poder identificar os pagamentos. - - - + Double-click to edit address or label Clique duas vezes para editar o endereço ou o rótulo - + Create a new address Criar um novo endereço - + Copy the currently selected address to the system clipboard Copie o endereço selecionado para a área de transferência - + &New Address - + &Novo Endereço - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Estes são os seus endereços CasinoCoin para receber pagamentos. Poderá enviar um endereço diferente para cada remetente para poder identificar os pagamentos. + + + &Copy Address - + &Copiar Endereço - + Show &QR Code - Mostrar &Código QR + Mostrar Código &QR - - Sign a message to prove you own this address - Assine uma mensagem para provar que é dono deste endereço + + Sign a message to prove you own a CasinoCoin address + Assine uma mensagem para provar que é dono de um endereço CasinoCoin - - &Sign Message - &Assinar Mensagem + + Sign &Message + Assinar &Mensagem - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Eliminar o endereço selecionado da lista. Apenas endereços de envio podem ser eliminados. + + Delete the currently selected address from the list + Apagar o endereço selecionado da lista - + + Export the data in the current tab to a file + Exportar os dados no separador actual para um ficheiro + + + + &Export + &Exportar + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verifique a mensagem para assegurar que foi assinada com o endereço CasinoCoin especificado + + + + &Verify Message + &Verificar Mensagem + + + &Delete - &Eliminar + E&liminar - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Estes são os seus endereços CasinoCoin para enviar pagamentos. Verifique sempre o valor e a morada de envio antes de enviar moedas. + + + Copy &Label - + Copiar &Rótulo - + &Edit - + &Editar - + + Send &Coins + Enviar &Moedas + + + Export Address Book Data - Exportar de dados do Livro de Endereços + Exportar dados do Livro de Endereços - + Comma separated file (*.csv) Ficheiro separado por vírgulas (*.csv) - + Error exporting Erro ao exportar - + Could not write to file %1. - Could not write to file %1. + Não foi possível escrever para o ficheiro %1. AddressTableModel - + Label Rótulo - + Address Endereço - + (no label) (Sem rótulo) @@ -144,974 +182,951 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open AskPassphraseDialog - + Passphrase Dialog - + Diálogo de Frase-Passe - + Enter passphrase Escreva a frase de segurança - + New passphrase Nova frase de segurança - + Repeat new passphrase Repita a nova frase de segurança - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - Escreva a nova frase de seguraça da sua carteira. <br/> Por favor, use uma frase de <b>10 ou mais caracteres aleatórios,</b> ou <b>oito ou mais palavras.</b> + Escreva a nova frase de seguraça da sua carteira. <br/> Por favor, use uma frase de <b>10 ou mais caracteres aleatórios,</b> ou <b>oito ou mais palavras</b>. - + Encrypt wallet Encriptar carteira - + This operation needs your wallet passphrase to unlock the wallet. A sua frase de segurança é necessária para desbloquear a carteira. - + Unlock wallet Desbloquear carteira - + This operation needs your wallet passphrase to decrypt the wallet. A sua frase de segurança é necessária para desencriptar a carteira. - + Decrypt wallet Desencriptar carteira - + Change passphrase Alterar frase de segurança - + Enter the old and new passphrase to the wallet. Escreva a frase de segurança antiga seguida da nova para a carteira. - + Confirm wallet encryption Confirmar encriptação da carteira - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - AVISO: Se encriptar a carteira e perder a sua senha irá <b>perder todos os seus BITCOINS!</b> Tem a certeza de que deseja encriptar a carteira? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Atenção: Se encriptar a carteira e perder a sua senha irá <b>PERDER TODOS OS SEUS CASINOCOINS</b>! - - + + Are you sure you wish to encrypt your wallet? + Tem a certeza que deseja encriptar a carteira? + + + + 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. + IMPORTANTE: Qualquer cópia de segurança anterior da carteira deverá ser substituída com o novo, actualmente encriptado, ficheiro de carteira. Por razões de segurança, cópias de segurança não encriptadas efectuadas anteriormente do ficheiro da carteira tornar-se-ão inúteis assim que começar a usar a nova carteira encriptada. + + + + + Warning: The Caps Lock key is on! + Atenção: A tecla Caps Lock está activa! + + + + Wallet encrypted Carteira encriptada - - Bitcoin 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. - O cliente Bitcoin irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus bitcoins de serem roubados por programas maliciosos que infectem o seu computador. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + O cliente CasinoCoin irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus casinocoins de serem roubados por programas maliciosos que infectem o seu computador. - - - Warning: The Caps Lock key is on. - Atenção: A tecla Caps Lock está activa. - - - - - - + + + + Wallet encryption failed A encriptação da carteira falhou - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. A encriptação da carteira falhou devido a um erro interno. A carteira não foi encriptada. - - + + The supplied passphrases do not match. As frases de segurança fornecidas não coincidem. - + Wallet unlock failed O desbloqueio da carteira falhou - - - + + + The passphrase entered for the wallet decryption was incorrect. A frase de segurança introduzida para a desencriptação da carteira estava incorreta. - + Wallet decryption failed A desencriptação da carteira falhou - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. A frase de segurança da carteira foi alterada com êxito. BitcoinGUI - - Bitcoin Wallet - Carteira Bitcoin - - - + Sign &message... - + Assinar &mensagem... - - Show/Hide &Bitcoin - Mostrar/Ocultar &Bitcoin - - - + Synchronizing with network... Sincronizando com a rede... - + &Overview - &Visão geral + Visã&o geral - + Show general overview of wallet Mostrar visão geral da carteira - + &Transactions &Transações - + Browse transaction history Navegar pelo histórico de transações - - &Address Book - &Livro de endereços - - - + Edit the list of stored addresses and labels Editar a lista de endereços e rótulos - - &Receive coins - &Receber moedas - - - + Show the list of addresses for receiving payments Mostrar a lista de endereços para receber pagamentos - - &Send coins - &Enviar moedas - - - - Prove you control an address - Prove que controla um endereço - - - + E&xit - S&air + Fec&har - + Quit application Sair da aplicação - - &About %1 - &Acerca de %1 + + Show information about CasinoCoin + Mostrar informação sobre CasinoCoin - - Show information about Bitcoin - Mostrar informação sobre Bitcoin - - - + About &Qt Sobre &Qt - + Show information about Qt Mostrar informação sobre Qt - + &Options... &Opções... - + &Encrypt Wallet... - + E&ncriptar Carteira... - + &Backup Wallet... - + &Guardar Carteira... - + &Change Passphrase... - - - - - ~%n block(s) remaining - ~%n bloco restante~%n blocos restantes + Mudar &Palavra-passe... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Recuperados %1 de %2 blocos do histórico de transações (%3% completo) + + Importing blocks from disk... + Importando blocos do disco... - - &Export... - &Exportar... + + Reindexing blocks on disk... + Reindexando blocos no disco... - - Send coins to a Bitcoin address - + + Send coins to a CasinoCoin address + Enviar moedas para um endereço casinocoin - - Modify configuration options for Bitcoin - + + Modify configuration options for CasinoCoin + Modificar opções de configuração para casinocoin - - Show or hide the Bitcoin window - Mostrar ou Ocultar a janela Bitcoin - - - - Export the data in the current tab to a file - Exportar os dados no separador actual para um ficheiro - - - - Encrypt or decrypt wallet - Encriptar ou desencriptar carteira - - - + Backup wallet to another location Faça uma cópia de segurança da carteira para outra localização - + Change the passphrase used for wallet encryption Mudar a frase de segurança utilizada na encriptação da carteira - + &Debug window - + Janela de &depuração - + Open debugging and diagnostic console - + Abrir consola de diagnóstico e depuração - + &Verify message... - + &Verificar mensagem... - - Verify a message signature - + + + CasinoCoin + CasinoCoin - + + Wallet + Carteira + + + + &Send + &Enviar + + + + &Receive + &Receber + + + + &Addresses + E&ndereços + + + + &About CasinoCoin + &Sobre o CasinoCoin + + + + &Show / Hide + Mo&strar / Ocultar + + + + Show or hide the main Window + Mostrar ou esconder a Janela principal + + + + Encrypt the private keys that belong to your wallet + Encriptar as chaves privadas que pertencem à sua carteira + + + + Sign messages with your CasinoCoin addresses to prove you own them + Assine mensagens com os seus endereços CasinoCoin para provar que os controla + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verifique mensagens para assegurar que foram assinadas com o endereço CasinoCoin especificado + + + &File &Ficheiro - + &Settings - &Configurações + Con&figurações - + &Help - &Ajuda + A&juda - + Tabs toolbar Barra de separadores - - Actions toolbar - Barra de ações - - - - + + [testnet] - [testnet] + [rede de testes] - - - Bitcoin client - Cliente Bitcoin + + CasinoCoin client + Cliente CasinoCoin - - %n active connection(s) to Bitcoin network - %n ligação ativa à rede Bitcoin%n ligações ativas à rede Bitcoin + + %n active connection(s) to CasinoCoin network + %n ligação ativa à rede CasinoCoin%n ligações ativas à rede CasinoCoin - - Downloaded %1 blocks of transaction history. - Recuperados %1 blocos do histórico de transações. + + No block source available... + Nenhum bloco fonto disponível + + + + Processed %1 of %2 (estimated) blocks of transaction history. + Processados %1 dos %2 blocos (estimados) do histórico de transacções. + + + + Processed %1 blocks of transaction history. + Processados %1 blocos do histórico de transações. - - %n second(s) ago - %n segundo%n segundos - - - - %n minute(s) ago - %n minutos%n minutos - - - - %n hour(s) ago + + %n hour(s) %n hora%n horas - - %n day(s) ago + + %n day(s) %n dia%n dias + + + %n week(s) + %n semana%n semanas + - + + %1 behind + %1 em atraso + + + + Last received block was generated %1 ago. + Último bloco recebido foi gerado há %1 atrás. + + + + Transactions after this will not yet be visible. + Transações posteriores poderão não ser imediatamente visíveis. + + + + Error + Erro + + + + Warning + Aviso + + + + Information + Informação + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Esta transação tem um tamanho superior ao limite máximo. Poderá enviá-la pagando uma taxa de %1, que será entregue ao nó que processar a sua transação e ajudará a suportar a rede. Deseja pagar a taxa? + + + Up to date Atualizado - + Catching up... Recuperando... - - Last received block was generated %1. - Último bloco recebido foi gerado há %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Esta transação tem um tamanho superior ao limite máximo. Poderá enviá-la pagando uma taxa de %1 que será entregue ao nó que processar a sua transação e ajudará a suportar a rede. Deseja pagar a taxa? - - - + Confirm transaction fee - + Confirme a taxa de transação - + Sent transaction Transação enviada - + Incoming transaction Transação recebida - + Date: %1 Amount: %2 Type: %3 Address: %4 Data: %1 -Quantidade: %2 +Quantia: %2 Tipo: %3 -Endereço: %4 +Endereço: %4 + - + + + URI handling + Manuseamento URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI não foi lido correctamente! Isto pode ser causado por um endereço CasinoCoin inválido ou por parâmetros URI malformados. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> A carteira está <b>encriptada</b> e atualmente <b>desbloqueada</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> A carteira está <b>encriptada</b> e atualmente <b>bloqueada</b> - - Backup Wallet - Cópia de Segurança da Carteira - - - - Wallet Data (*.dat) - Dados da Carteira (*.dat) - - - - Backup Failed - Cópia de Segurança Falhada - - - - There was an error trying to save the wallet data to the new location. - Ocorreu um erro ao tentar guardar os dados da carteira na nova localização. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ocorreu um erro fatal. O CasinoCoin não pode continuar com segurança e irá fechar. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Janela - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Escolha a subdivisão unitária a ser mostrada por defeito na aplicação e ao enviar moedas - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Alerta da Rede EditAddressDialog - + Edit Address Editar Endereço - + &Label &Rótulo - + The label associated with this address book entry O rótulo a ser associado com esta entrada do livro de endereços - + &Address - &Endereço + E&ndereço - + The address associated with this address book entry. This can only be modified for sending addresses. O endereço associado com esta entrada do livro de endereços. Apenas poderá ser modificado para endereços de saída. - + New receiving address Novo endereço de entrada - + New sending address Novo endereço de saída - + Edit receiving address - &Ajuda + Editar endereço de entrada - + Edit sending address Editar endereço de saída - + The entered address "%1" is already in the address book. O endereço introduzido "%1" já se encontra no livro de endereços. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + O endereço introduzido "%1" não é um endereço casinocoin válido. - + Could not unlock wallet. Impossível desbloquear carteira. - + New key generation failed. Falha ao gerar nova chave. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versão - + Usage: Utilização: - - options - + + command-line options + opções da linha de comandos - + UI options - + Opções de UI - + Set language, for example "de_DE" (default: system locale) Definir linguagem, por exemplo "pt_PT" (por defeito: linguagem do sistema) - + Start minimized Iniciar minimizado - + Show splash screen on startup (default: 1) Mostrar animação ao iniciar (por defeito: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - + + Options + Opções - + + &Main + &Principal + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Taxa de transação opcional por KB que ajuda a assegurar que as suas transações serão processadas rapidamente. A maioria das transações tem 1 kB. + + + Pay transaction &fee Pagar &taxa de transação - - Main - Geral + + Automatically start CasinoCoin after logging in to the system. + Começar o CasinoCoin automaticamente ao iniciar sessão no sistema. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Taxa de transação opcional por kB que ajuda a assegurar que as suas transações serão processadas rapidamente. A maioria das transações tem 1 kB. Taxa de 0.01 recomendada. + + &Start CasinoCoin on system login + &Começar o CasinoCoin ao iniciar o sistema - - &Start Bitcoin on system login - + + Reset all client options to default. + Repôr todas as opções. - - Automatically start Bitcoin after logging in to the system - + + &Reset Options + &Repôr Opções - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - + + &Network + &Rede - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Pode assinar mensagens com os seus endereços para provar que são seus. Tenha atenção ao assinar mensagens ambíguas, pois ataques de phishing podem tentar enganá-lo, de modo a assinar a sua identidade para os atacantes. Apenas assine declarações completamente detalhadas com as quais concorde. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Abrir a porta do cliente casinocoin automaticamente no seu router. Isto penas funciona se o seu router suportar UPnP e este se encontrar ligado. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - O endereço a utilizar para assinar a mensagem (p.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Escolher endereço - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Paste address from clipboard - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Escreva aqui a mensagem que deseja assinar - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Clique "Assinar mensagem" para aceder á assinatura - - - - Sign a message to prove you own this address - Assine uma mensagem para provar que é dono deste endereço - - - - &Sign Message - &Assinar Mensagem - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduza um endereço Bitcoin (p.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Erro ao assinar - - - - %1 is not a valid address. - %1 não é um endereço válido. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - A chave privada para %1 não está disponível. - - - - Sign failed - Falha ao assinar - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Mapear porta usando &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Abrir a porta do cliente bitcoin automaticamente no seu router. Isto penas funciona se o seu router suportar UPnP e este se encontrar ligado. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Ligar à rede CasinoCoin através de um proxy SOCKS (p.ex. quando ligar através de Tor). - - &Connect through SOCKS4 proxy: - &Ligar através de proxy SOCKS4: + + &Connect through SOCKS proxy: + Ligar através de proxy SO&CKS: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Ligar à rede Bitcoin através de um proxy SOCKS4 (p.ex. quando ligar através de Tor) - - - + Proxy &IP: - + &IP do proxy: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) Endereço IP do proxy (p.ex. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Porta do proxy (p.ex. 1234) + + &Port: + &Porta: - - - OptionsDialog - - Options - Opções + + Port of the proxy (e.g. 9050) + Porta do proxy (p.ex. 9050) + + + + SOCKS &Version: + &Versão SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Versão do proxy SOCKS (p.ex. 5) + + + + &Window + &Janela + + + + Show only a tray icon after minimizing the window. + Apenas mostrar o ícone da bandeja após minimizar a janela. + + + + &Minimize to the tray instead of the taskbar + &Minimizar para a bandeja e não para a barra de ferramentas + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimize ao invés de sair da aplicação quando a janela é fechada. Com esta opção selecionada, a aplicação apenas será encerrada quando escolher Sair da aplicação no menú. + + + + M&inimize on close + M&inimizar ao fechar + + + + &Display + Vis&ualização + + + + User Interface &language: + &Linguagem da interface de utilizador: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + A linguagem da interface do utilizador pode ser definida aqui. Esta definição entrará em efeito após reiniciar o CasinoCoin. + + + + &Unit to show amounts in: + &Unidade a usar em quantias: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Escolha a subdivisão unitária a ser mostrada por defeito na aplicação e ao enviar moedas. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Se mostrar, ou não, os endereços CasinoCoin na lista de transações. + + + + &Display addresses in transaction list + Mostrar en&dereços na lista de transações + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + &Apply + &Aplicar + + + + default + padrão + + + + Confirm options reset + Confirme a reposição de opções + + + + Some settings may require a client restart to take effect. + Algumas opções requerem o reinício do programa para funcionar. + + + + Do you want to proceed? + Deseja proceder? + + + + + Warning + Aviso + + + + + This setting will take effect after restarting CasinoCoin. + Esta opção entrará em efeito após reiniciar o CasinoCoin. + + + + The supplied proxy address is invalid. + O endereço de proxy introduzido é inválido. OverviewPage - + Form Formulário - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + A informação mostrada poderá estar desatualizada. A sua carteira sincroniza automaticamente com a rede CasinoCoin depois de estabelecer ligação, mas este processo ainda não está completo. - + Balance: Saldo: - - Number of transactions: - Número de transações: - - - + Unconfirmed: Não confirmado: - + Wallet - + Carteira - + + Immature: + Imaturo: + + + + Mined balance that has not yet matured + O saldo minado ainda não maturou + + + <b>Recent transactions</b> <b>Transações recentes</b> - + Your current balance - O seu saldo actual + O seu saldo atual - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Total de transações ainda não confirmadas, e que não estão contabilizadas ainda no seu saldo actual - - Total number of transactions in wallet - Número total de transações na carteira - - - - + + out of sync - + fora de sincronia + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Impossível começar o modo clicar-para-pagar com casinocoin: QRCodeDialog - + QR Code Dialog - + Diálogo de Código QR - - QR Code - Código QR - - - + Request Payment Requisitar Pagamento - + Amount: Quantia: - - BTC - BTC - - - + Label: Rótulo: - + Message: - Message: + Mensagem: - + &Save As... &Salvar Como... - + Error encoding URI into QR Code. - + Erro ao codificar URI em Código QR. - + + The entered amount is invalid, please check. + A quantia introduzida é inválida, por favor verifique. + + + Resulting URI too long, try to reduce the text for label / message. URI resultante muito longo. Tente reduzir o texto do rótulo / mensagem. - + Save QR Code - + Guardar Código QR - + PNG Images (*.png) Imagens PNG (*.png) @@ -1119,453 +1134,713 @@ Endereço: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Nome do Cliente - - - - - - - - - + + + + + + + + + + N/A - + N/D - + Client version - + Versão do Cliente - + &Information - + &Informação - - Client - + + Using OpenSSL version + Usando versão OpenSSL - + Startup time - + Tempo de início - + Network - + Rede - + Number of connections - + Número de ligações - + On testnet - + Em rede de testes - + Block chain - + Cadeia de blocos - + Current number of blocks - + Número actual de blocos - + Estimated total blocks - + Total estimado de blocos - + Last block time - + Tempo do último bloco - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Abrir - + + Command-line options + Opções de linha de comandos + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Mostrar a mensagem de ajuda do CasinoCoin-Qt para obter uma lista com possíveis opções a usar na linha de comandos. + + + + &Show + Mo&strar + + + &Console - + &Consola - + Build date - + Data de construção - + + CasinoCoin - Debug window + CasinoCoin - Janela de depuração + + + + CasinoCoin Core + Núcleo CasinoCoin + + + + Debug log file + Ficheiro de registo de depuração + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Abrir o ficheiro de registo de depuração da pasta de dados actual. Isto pode demorar alguns segundos para ficheiros de registo maiores. + + + Clear console - + Limpar consola - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Bem-vindo à consola RPC CasinoCoin. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Use as setas para cima e para baixo para navegar no histórico e <b>Ctrl-L</b> para limpar o ecrã. - + Type <b>help</b> for an overview of available commands. - + Digite <b>help</b> para visualizar os comandos disponíveis. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Enviar Moedas - + Send to multiple recipients at once Enviar para múltiplos destinatários de uma vez - - &Add Recipient - + + Add &Recipient + Adicionar &Destinatário - + Remove all transaction fields Remover todos os campos da transação - + Clear &All - + &Limpar Tudo - + Balance: Saldo: - + 123.456 BTC 123.456 BTC - + Confirm the send action Confirme ação de envio - - &Send + + S&end &Enviar - + <b>%1</b> to %2 (%3) <b>%1</b> para %2 (%3) - + Confirm send coins Confirme envio de moedas - + Are you sure you want to send %1? Tem a certeza que deseja enviar %1? - + and e - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. O endereço de destino não é válido, por favor verifique. - + The amount to pay must be larger than 0. A quantia a pagar deverá ser maior que 0. - + The amount exceeds your balance. - + A quantia excede o seu saldo. - + The total exceeds your balance when the %1 transaction fee is included. - + O total excede o seu saldo quando a taxa de transação de %1 for incluída. - + Duplicate address found, can only send to each address once per send operation. - + Endereço duplicado encontrado, apenas poderá enviar uma vez para cada endereço por cada operação de envio. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Erro: A criação da transacção falhou! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Erro: A transação foi rejeitada. Isso poderá acontecer se algumas das moedas na sua carteira já tiverem sido gastas, se por exemplo tiver usado uma cópia do ficheiro wallet.dat e as moedas foram gastas na cópia mas não foram marcadas como gastas aqui. SendCoinsEntry - + Form Formulário - + A&mount: - Q&uantia: + Qu&antia: - + Pay &To: - Pagar &A: + &Pagar A: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + O endereço para onde enviar o pagamento (p.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Escreva um rótulo para este endereço para o adicionar ao seu livro de endereços - + &Label: - &Rótulo: + Rótu&lo: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - O endereço para onde enviar o pagamento (p.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Escolher endereço do livro de endereços - + Alt+A Alt+A - + Paste address from clipboard Cole endereço da área de transferência - + Alt+P Alt+P - + Remove this recipient Remover este destinatário - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduza um endereço Bitcoin (p.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduza um endereço CasinoCoin (p.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Assinaturas - Assinar / Verificar uma Mensagem + + + + &Sign Message + A&ssinar Mensagem + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Pode assinar mensagens com os seus endereços para provar que são seus. Tenha atenção ao assinar mensagens ambíguas, pois ataques de phishing podem tentar enganá-lo, de modo a assinar a sua identidade para os atacantes. Apenas assine declarações completamente detalhadas com as quais concorde. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + O endereço a utilizar para assinar a mensagem (p.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Escolher endereço do livro de endereços + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Cole endereço da área de transferência + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Escreva aqui a mensagem que deseja assinar + + + + Signature + Assinatura + + + + Copy the current signature to the system clipboard + Copiar a assinatura actual para a área de transferência + + + + Sign the message to prove you own this CasinoCoin address + Assine uma mensagem para provar que é dono deste endereço CasinoCoin + + + + Sign &Message + Assinar &Mensagem + + + + Reset all sign message fields + Repôr todos os campos de assinatura de mensagem + + + + + Clear &All + Limpar &Tudo + + + + &Verify Message + &Verificar Mensagem + + + + Enter the signing 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. + Introduza o endereço de assinatura, mensagem (assegure-se de copiar quebras de linha, espaços, tabuladores, etc. exactamente) e assinatura abaixo para verificar a mensagem. Tenha atenção para não ler mais na assinatura do que o que estiver na mensagem assinada, para evitar ser enganado por um atacante que se encontre entre si e quem assinou a mensagem. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + O endereço utilizado para assinar a mensagem (p.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verifique a mensagem para assegurar que foi assinada com o endereço CasinoCoin especificado + + + + Verify &Message + Verificar &Mensagem + + + + Reset all verify message fields + Repôr todos os campos de verificação de mensagem + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduza um endereço CasinoCoin (p.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Clique "Assinar mensagem" para gerar a assinatura + + + + Enter CasinoCoin signature + Introduza assinatura CasinoCoin + + + + + The entered address is invalid. + O endereço introduzido é inválido. + + + + + + + Please check the address and try again. + Por favor verifique o endereço e tente de novo. + + + + + The entered address does not refer to a key. + O endereço introduzido não refere a chave alguma. + + + + Wallet unlock was cancelled. + O desbloqueio da carteira foi cancelado. + + + + Private key for the entered address is not available. + A chave privada para o endereço introduzido não está disponível. + + + + Message signing failed. + Assinatura de mensagem falhou. + + + + Message signed. + Mensagem assinada. + + + + The signature could not be decoded. + A assinatura não pôde ser descodificada. + + + + + Please check the signature and try again. + Por favor verifique a assinatura e tente de novo. + + + + The signature did not match the message digest. + A assinatura não condiz com o conteúdo da mensagem. + + + + Message verification failed. + Verificação da mensagem falhou. + + + + Message verified. + Mensagem verificada. + + + + SplashScreen + + + The CasinoCoin developers + Os programadores CasinoCoin + + + + [testnet] + [rede de testes] TransactionDesc - - Open for %1 blocks - Aberto para %1 blocos - - - + Open until %1 Aberto até %1 - - %1/offline? - %1/desligado? + + %1/offline + %1/desligado - + %1/unconfirmed %1/não confirmada - + %1 confirmations %1 confirmações - - <b>Status:</b> - <b>Estado:</b> + + Status + Estado + + + + , broadcast through %n node(s) + , transmitida através de %n nó, transmitida através de %n nós - + + Date + Data + + + + Source + Origem + + + + Generated + Gerado + + + + + From + De + + + + + + To + Para + + + + + own address + endereço próprio + + + + label + rótulo + + + + + + + + Credit + Crédito + + + + matures in %n more block(s) + matura daqui por %n blocomatura daqui por %n blocos + + + + not accepted + não aceite + + + + + + + Debit + Débito + + + + Transaction fee + Taxa de transação + + + + Net amount + Valor líquido + + + + Message + Mensagem + + + + Comment + Comentário + + + + Transaction ID + ID da Transação + + + + Generated coins must mature 120 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. + Moedas geradas deverão maturar por 120 blocos antes de poderem ser gastas. Quando gerou este bloco, ele foi transmitido para a rede para ser incluído na cadeia de blocos. Se a inclusão na cadeia de blocos falhar, irá mudar o estado para "não aceite" e as moedas não poderão ser gastas. Isto poderá acontecer ocasionalmente se outro nó da rede gerar um bloco a poucos segundos de diferença do seu. + + + + Debug information + Informação de depuração + + + + Transaction + Transação + + + + Inputs + Entradas + + + + Amount + Quantia + + + + true + verdadeiro + + + + false + falso + + + , has not been successfully broadcast yet , ainda não foi transmitida com sucesso - - - , broadcast through %1 node - , transmitida através de %1 nó + + + Open for %n more block(s) + Aberta por mais %n blocoAberta por mais %n blocos - - , broadcast through %1 nodes - , transmitida através de %1 nós - - - - <b>Date:</b> - <b>Data:</b> - - - - <b>Source:</b> Generated<br> - <b>Fonte:</b> Geradas<br> - - - - - <b>From:</b> - <b>De:</b> - - - + unknown desconhecido - - - - - <b>To:</b> - <b>Para:</b> - - - - (yours, label: - (seu, rótulo: - - - - (yours) - (seu) - - - - - - - <b>Credit:</b> - <b>Crédito:</b> - - - - (%1 matures in %2 more blocks) - (%1 matura daqui por %2 blocos) - - - - (not accepted) - (não aceite) - - - - - - <b>Debit:</b> - <b>Débito:</b> - - - - <b>Transaction fee:</b> - <b>Taxa de transação:</b> - - - - <b>Net amount:</b> - <b>Valor líquido:</b> - - - - Message: - Mensagem: - - - - Comment: - Comentário: - - - - Transaction ID: - ID da Transação: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Moedas geradas deverão maturar por 120 blocos antes de poderem ser gastas. Quando gerou este bloco, ele foi transmitido para a rede para ser incluído na cadeia de blocos. Se a inclusão na cadeia de blocos falhar, irá mudar o estado para "não aceite" e as moedas não poderão ser gastas. Isto poderá acontecer ocasionalmente se outro nó da rede gerar um bloco a poucos segundos de diferença do seu. - TransactionDescDialog - + Transaction details Detalhes da transação - + This pane shows a detailed description of the transaction Esta janela mostra uma descrição detalhada da transação @@ -1573,117 +1848,117 @@ Endereço: %4 TransactionTableModel - + Date Data - + Type Tipo - + Address Endereço - + Amount Quantia - - Open for %n block(s) - Aberto para %n blocoAberto para %n blocos + + Open for %n more block(s) + Aberta por mais %n blocoAberta por mais %n blocos - + Open until %1 Aberto até %1 - + Offline (%1 confirmations) Desligado (%1 confirmação) - + Unconfirmed (%1 of %2 confirmations) Não confirmada (%1 de %2 confirmações) - + Confirmed (%1 confirmations) Confirmada (%1 confirmação) - - Mined balance will be available in %n more blocks - Saldo minado estará disponível daqui por %n blocoSaldo minado estará disponível daqui por %n blocos + + Mined balance will be available when it matures in %n more block(s) + Saldo minado ficará disponível quando maturar, daqui por %n blocoSaldo minado ficará disponível quando maturar, daqui por %n blocos - + This block was not received by any other nodes and will probably not be accepted! Este bloco não foi recebido por outros nós e provavelmente não será aceite pela rede! - + Generated but not accepted Gerado mas não aceite - + Received with Recebido com - + Received from Recebido de - + Sent to Enviado para - + Payment to yourself Pagamento ao próprio - + Mined Minado - + (n/a) (n/d) - + Transaction status. Hover over this field to show number of confirmations. Estado da transação. Pairar por cima deste campo para mostrar o número de confirmações. - + Date and time that the transaction was received. Data e hora a que esta transação foi recebida. - + Type of transaction. Tipo de transação. - + Destination address of transaction. Endereço de destino da transação. - + Amount removed from or added to balance. Quantia retirada ou adicionada ao saldo. @@ -1691,817 +1966,967 @@ Endereço: %4 TransactionView - - + + All Todas - + Today Hoje - + This week Esta semana - + This month Este mês - + Last month Mês passado - + This year Este ano - + Range... Período... - + Received with Recebida com - + Sent to Enviada para - + To yourself Para si - + Mined Minadas - + Other Outras - + Enter address or label to search Escreva endereço ou rótulo a procurar - + Min amount Quantia mínima - + Copy address Copiar endereço - + Copy label Copiar rótulo - + Copy amount Copiar quantia - + + Copy transaction ID + Copiar ID da Transação + + + Edit label Editar rótulo - + Show transaction details - + Mostrar detalhes da transação - + Export Transaction Data Exportar Dados das Transações - + Comma separated file (*.csv) Ficheiro separado por vírgula (*.csv) - + Confirmed Confirmada - + Date Data - + Type Tipo - + Label Rótulo - + Address Endereço - + Amount Quantia - + ID ID - + Error exporting Erro ao exportar - + Could not write to file %1. Impossível escrever para o ficheiro %1. - + Range: Período: - + to até - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copie o endereço selecionado para a área de transferência do sistema - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Enviando... + + Send Coins + Enviar Moedas - WindowOptionsPage + WalletView - - Window - + + &Export + &Exportar - - &Minimize to the tray instead of the taskbar - &Minimizar para a bandeja e não para a barra de ferramentas + + Export the data in the current tab to a file + Exportar os dados no separador actual para um ficheiro - - Show only a tray icon after minimizing the window - Apenas mostrar o ícone da bandeja depois de minimizar a janela + + Backup Wallet + Cópia de Segurança da Carteira - - M&inimize on close - + + Wallet Data (*.dat) + Dados da Carteira (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimize ao invés de sair da aplicação quando a janela é fechada. Com esta opção selecionada, a aplicação apenas será encerrada quando escolher Sair da aplicação no menú. + + Backup Failed + Cópia de Segurança Falhou + + + + There was an error trying to save the wallet data to the new location. + Ocorreu um erro ao tentar guardar os dados da carteira na nova localização. + + + + Backup Successful + Cópia de Segurança Bem Sucedida + + + + The wallet data was successfully saved to the new location. + Os dados da carteira foram salvos com sucesso numa nova localização. bitcoin-core - - Bitcoin version - Versão Bitcoin + + CasinoCoin version + Versão CasinoCoin - + Usage: Utilização: - - Send command to -server or bitcoind - Enviar comando para -server ou bitcoind + + Send command to -server or casinocoind + Enviar comando para -server ou casinocoind - + List commands Listar comandos - + Get help for a command Obter ajuda para um comando - + Options: Opções: - - Specify configuration file (default: bitcoin.conf) - Especificar ficheiro de configuração (por defeito: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Especificar ficheiro de configuração (por defeito: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Especificar ficheiro pid (por defeito: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Especificar ficheiro pid (por defeito: casinocoind.pid) - - Generate coins - Gerar moedas - - - - Don't generate coins - Não gerar moedas - - - + Specify data directory Especificar pasta de dados - + Set database cache size in megabytes (default: 25) Definir o tamanho da cache de base de dados em megabytes (por defeito: 25) - - Set database disk log size in megabytes (default: 100) - Definir o tamanho de registo do disco de base de dados em megabytes (por defeito: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Escute por ligações em <port> (por defeito: 47950 ou testnet: 17950) - - Specify connection timeout (in milliseconds) - Especificar tempo de espera da ligação (em millisegundos) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Escute por ligações em <port> (por defeito: 8333 ou testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Manter no máximo <n> ligações a outros nós da rede (por defeito: 125) - - Connect only to the specified node - Apenas ligar ao nó especificado - - - + Connect to a node to retrieve peer addresses, and disconnect - + Ligar a um nó para recuperar endereços de pares, e desligar - + Specify your own public address - + Especifique o seu endereço público - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) Tolerância para desligar nós mal-formados (por defeito: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Número de segundos a impedir que nós mal-formados se liguem de novo (por defeito: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Armazenamento intermédio de recepção por ligação, <n>*1000 bytes (por defeito: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Ocorreu um erro ao definir a porta %u do serviço RPC a escutar em IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Armazenamento intermédio de envio por ligação, <n>*1000 bytes (por defeito: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Escutar por ligações JSON-RPC em <port> (por defeito: 47970 ou rede de testes: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Aceitar comandos da consola e JSON-RPC - + Run in the background as a daemon and accept commands Correr o processo como um daemon e aceitar comandos - + Use the test network Utilizar a rede de testes - testnet - - Output extra debugging information + + Accept connections from outside (default: 1 if no -proxy or -connect) + Aceitar ligações externas (padrão: 1 sem -proxy ou -connect) + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, deverá definir rpcpassword no ficheiro de configuração : + %s +É recomendado que use a seguinte palavra-passe aleatória: +rpcuser=casinocoinrpc +rpcpassword=%s +(não precisa recordar esta palavra-passe) +O nome de utilizador e password NÃO DEVEM ser iguais. +Se o ficheiro não existir, crie-o com permissões de leitura apenas para o dono. +Também é recomendado definir alertnotify para que seja alertado sobre problemas; +por exemplo: alertnotify=echo %%s | mail -s "Alerta CasinoCoin" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Ocorreu um erro ao definir a porta %u do serviço RPC a escutar em IPv6, a usar IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Trancar a endereço específio e sempre escutar nele. Use a notação [anfitrião]:porta para IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Impossível trancar a pasta de dados %s. Provavelmente o CasinoCoin já está a ser executado. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Erro: A transação foi rejeitada. Isso poderá acontecer se algumas das moedas na sua carteira já tiverem sido gastas, se por exemplo tiver usado uma cópia do ficheiro wallet.dat e as moedas foram gastas na cópia mas não foram marcadas como gastas aqui. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Erro: Esta transação requer uma taxa de transação mínima de %s devido á sua quantia, complexidade, ou uso de fundos recebidos recentemente! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Executar comando quando um alerta relevante for recebido (no comando, %s é substituído pela mensagem) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Executar comando quando uma das transações na carteira mudar (no comando, %s é substituído pelo ID da Transação) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Definir tamanho máximo de transações de alta-/baixa-prioridade em bytes (por defeito: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Esta é uma versão de pré-lançamento - use à sua responsabilidade - não usar para minar ou aplicações comerciais + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Atenção: -paytxfee está definida com um valor muito alto! Esta é a taxa que irá pagar se enviar uma transação. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Atenção: As transações mostradas poderão não estar correctas! Poderá ter que atualizar ou outros nós poderão ter que atualizar. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Atenção: Por favor verifique que a data e hora do seu computador estão correctas! Se o seu relógio não estiver certo o CasinoCoin não irá funcionar correctamente. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Atenção: erro ao ler wallet.dat! Todas as chaves foram lidas correctamente, mas dados de transação ou do livro de endereços podem estar em falta ou incorrectos. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Atenção: wallet.dat corrupto, dados recuperados! wallet.dat original salvo como wallet.{timestamp}.bak em %s; se o seu saldo ou transações estiverem incorrectos deverá recuperar de uma cópia de segurança. + + + + Attempt to recover private keys from a corrupt wallet.dat + Tentar recuperar chaves privadas de um wallet.dat corrupto + + + + Block creation options: + Opções de criação de bloco: + + + + Connect only to the specified node(s) + Apenas ligar ao(s) nó(s) especificado(s) + + + + Corrupted block database detected + Cadeia de blocos corrompida detectada + + + + Discover own IP address (default: 1 when listening and no -externalip) + Descobrir endereço IP próprio (padrão: 1 ao escutar e sem -externalip) + + + + Do you want to rebuild the block database now? + Deseja reconstruir agora a cadeia de blocos? + + + + Error initializing block database + Erro ao inicializar a cadeia de blocos + + + + Error initializing wallet database environment %s! + Erro ao inicializar o ambiente de base de dados da carteira %s! + + + + Error loading block database + Erro ao carregar cadeia de blocos + + + + Error opening block database + Erro ao abrir a cadeia de blocos + + + + Error: Disk space is low! + Erro: Pouco espaço em disco! + + + + Error: Wallet locked, unable to create transaction! + Erro: Carteira bloqueada, incapaz de criar transação! + + + + Error: system error: + Erro: erro do sistema: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Falhou a escutar em qualquer porta. Use -listen=0 se quer isto. + + + + Failed to read block info + Falha ao ler info do bloco + + + + Failed to read block + Falha ao ler bloco + + + + Failed to sync block index + Falha ao sincronizar índice do bloco + + + + Failed to write block index + Falha ao escrever índice do bloco + + + + Failed to write block info + Falha ao escrever info do bloco + + + + Failed to write block + Falha ao escrever o bloco + + + + Failed to write file info + Falha ao escrever info do ficheiro + + + + Failed to write to coin database + Falha ao escrever na base de dados de moedas + + + + Failed to write transaction index + Falha ao escrever índice de transações + + + + Failed to write undo data + Falha ao escrever histórico de modificações + + + + Find peers using DNS lookup (default: 1 unless -connect) + Encontrar pares usando procura DNS (por defeito: 1 excepto -connect) + + + + Generate coins (default: 0) + Gerar moedas (por defeito: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Quantos blocos verificar ao começar (por defeito: 288, 0 = todos) + + + + How thorough the block verification is (0-4, default: 3) + Qual a minúcia na verificação de blocos (0-4, por defeito: 3) + + + + Not enough file descriptors available. + Descritores de ficheiros disponíveis são insuficientes. + + + + Rebuild block chain index from current blk000??.dat files + Reconstruir a cadeia de blocos dos ficheiros blk000??.dat actuais + + + + Set the number of threads to service RPC calls (default: 4) + Defina o número de processos para servir as chamadas RPC (por defeito: 4) + + + + Verifying blocks... + Verificando blocos... + + + + Verifying wallet... + Verificando a carteira... + + + + Imports blocks from external blk000??.dat file + Importar blocos de um ficheiro blk000??.dat externo + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Defina o número de processos de verificação (até 16, 0 = automático, <0 = disponibiliza esse número de núcleos livres, por defeito: 0) + + + + Information + Informação + + + + Invalid -tor address: '%s' + Endereço -tor inválido: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Quantia inválida para -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Quantia inválida para -mintxfee=<amount>: '%s' + + + + Maintain a full transaction index (default: 0) + Manter índice de transações completo (por defeito: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Armazenamento intermédio de recepção por ligação, <n>*1000 bytes (por defeito: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Armazenamento intermédio de envio por ligação, <n>*1000 bytes (por defeito: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Apenas aceitar cadeia de blocos coincidente com marcas de verificação internas (por defeito: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Apenas ligar a nós na rede <net> (IPv4, IPv6 ou Tor) + + + + Output extra debugging information. Implies all other -debug* options + Produzir informação de depuração extra. Implica todas as outras opções -debug* + + + + Output extra network debugging information Produzir informação de depuração extraordinária - + Prepend debug output with timestamp Preceder informação de depuração com selo temporal - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Opções SSL: (ver a Wiki CasinoCoin para instruções de configuração SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Selecione a versão do proxy socks a usar (4-5, padrão: 5) + + + Send trace/debug info to console instead of debug.log file Enviar informação de rastreio/depuração para a consola e não para o ficheiro debug.log - + Send trace/debug info to debugger Enviar informação de rastreio/depuração para o depurador - + + Set maximum block size in bytes (default: 250000) + Definir tamanho máximo de um bloco em bytes (por defeito: 250000) + + + + Set minimum block size in bytes (default: 0) + Definir tamanho minímo de um bloco em bytes (por defeito: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Encolher ficheiro debug.log ao iniciar o cliente (por defeito: 1 sem -debug definido) + + + + Signing transaction failed + Falhou assinatura da transação + + + + Specify connection timeout in milliseconds (default: 5000) + Especificar tempo de espera da ligação em millisegundos (por defeito: 5000) + + + + System error: + Erro de sistema: + + + + Transaction amount too small + Quantia da transação é muito baixa + + + + Transaction amounts must be positive + Quantia da transação deverá ser positiva + + + + Transaction too large + Transação grande demais + + + + Use UPnP to map the listening port (default: 0) + Usar UPnP para mapear a porta de escuta (padrão: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Usar UPnP para mapear a porta de escuta (padrão: 1 ao escutar) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Utilizar proxy para aceder a serviços escondidos Tor (por defeito: mesmo que -proxy) + + + Username for JSON-RPC connections Nome de utilizador para ligações JSON-RPC - + + Warning + Aviso + + + + Warning: This version is obsolete, upgrade required! + Atenção: Esta versão está obsoleta, é necessário actualizar! + + + + You need to rebuild the databases using -reindex to change -txindex + Necessita reconstruir as bases de dados usando -reindex para mudar -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat corrupta, recuperação falhou + + + Password for JSON-RPC connections Palavra-passe para ligações JSON-RPC - - Listen for JSON-RPC connections on <port> (default: 8332) - Escutar por ligações JSON-RPC na porta <port> (por defeito: 8332) - - - + Allow JSON-RPC connections from specified IP address Permitir ligações JSON-RPC do endereço IP especificado - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comandos para o nó a correr em <ip> (por defeito: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - Executar comando quando mudar o melhor bloco (na consola, %s é substituído pela hash do bloco) + Executar comando quando mudar o melhor bloco (no comando, %s é substituído pela hash do bloco) - + Upgrade wallet to latest format Atualize a carteira para o formato mais recente - + Set key pool size to <n> (default: 100) Definir o tamanho da memória de chaves para <n> (por defeito: 100) - + Rescan the block chain for missing wallet transactions Reexaminar a cadeia de blocos para transações em falta na carteira - - How many blocks to check at startup (default: 2500, 0 = all) - Verificar quantos blocos ao iniciar (por defeito: 2500, 0 = todos) - - - - How thorough the block verification is (0-6, default: 1) - Minuciosidade da verificação de blocos é (0-6, por defeito: 1) - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Opções SSL: (ver a Wiki Bitcoin para instruções de configuração SSL) - - - + Use OpenSSL (https) for JSON-RPC connections Usar OpenSSL (https) para ligações JSON-RPC - + Server certificate file (default: server.cert) Ficheiro de certificado do servidor (por defeito: server.cert) - + Server private key (default: server.pem) Chave privada do servidor (por defeito: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifras aceitáveis (por defeito: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - - - - + This help message Esta mensagem de ajuda - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Impossível trancar a pasta de dados %s. Provavelmente o Bitcoin já está a ser executado. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Incapaz de vincular a %s neste computador (vínculo retornou erro %d, %s) - + Connect through socks proxy - + Ligar através de um proxy socks - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - + Allow DNS lookups for -addnode, -seednode and -connect - + Permitir procuras DNS para -addnode, -seednode e -connect - - Pass DNS requests to (SOCKS5) proxy - - - - + Loading addresses... - A carregar endereços... + Carregar endereços... - - Error loading blkindex.dat - Erro ao carregar blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Erro ao carregar wallet.dat: Carteira danificada - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Erro ao carregar wallet.dat: A Carteira requer uma versão mais recente do Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Erro ao carregar wallet.dat: A Carteira requer uma versão mais recente do CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - A Carteira precisou ser reescrita: reinicie o Bitcoin para completar + + Wallet needed to be rewritten: restart CasinoCoin to complete + A Carteira precisou ser reescrita: reinicie o CasinoCoin para completar - + Error loading wallet.dat Erro ao carregar wallet.dat - + Invalid -proxy address: '%s' - + Endereço -proxy inválido: '%s' - - Unknown network specified in -noproxy: '%s' - - - - + Unknown network specified in -onlynet: '%s' - + Rede desconhecida especificada em -onlynet: '%s' - + Unknown -socks proxy version requested: %i - + Versão desconhecida de proxy -socks requisitada: %i - + Cannot resolve -bind address: '%s' - + Não conseguiu resolver endereço -bind: '%s' - - Not listening on any port - - - - + Cannot resolve -externalip address: '%s' - + Não conseguiu resolver endereço -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - + Quantia inválida para -paytxfee=<amount>: '%s' - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - Erro: Carteira bloqueada, incapaz de criar transação - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Erro: Esta transação requer uma taxa de transação mínima de %s devido á sua quantia, complexidade, ou uso de fundos recebidos recentemente - - - - Error: Transaction creation failed - Error: Transaction creation failed - - - - Sending... - Enviando... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - + Invalid amount Quantia inválida - + Insufficient funds - Insufficient funds + Fundos insuficientes - + Loading block index... - A carregar índice de blocos... + Carregar índice de blocos... - + Add a node to connect to and attempt to keep the connection open Adicione um nó ao qual se ligar e tentar manter a ligação aberta - - Unable to bind to %s on this computer. Bitcoin is probably already running. - + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Incapaz de vincular à porta %s neste computador. Provavelmente o CasinoCoin já está a funcionar. - - Find peers using internet relay chat (default: 0) - Encontrar pares usando IRC (por defeito: 0) - - - - Accept connections from outside (default: 1) - Aceitar ligações externas (por defeito: 1) - - - - Find peers using DNS lookup (default: 1) - Encontrar pares usando procura DNS (por defeito: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Usar Universal Plug and Play para mapear porta de escuta (por defeito: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Usar Universal Plug and Play para mapear porta de escuta (por defeito: 0) - - - + Fee per KB to add to transactions you send - Fee per KB to add to transactions you send + Taxa por KB a adicionar a transações enviadas - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - + Loading wallet... - A carregar carteira... + Carregar carteira... - + Cannot downgrade wallet Impossível mudar a carteira para uma versão anterior - - Cannot initialize keypool - Impossível inicializar keypool - - - + Cannot write default address Impossível escrever endereço por defeito - + Rescanning... Reexaminando... - + Done loading Carregamento completo - + To use the %s option Para usar a opção %s - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, deverá definir uma palavra-passe de RPC no ficheiro de configuração : - %s -É recomendado que use a seguinte palavra-passe aleatória: -rpcuser=bitcoinrpc -rpcpassword=%s -(não precisa recordar esta palavra-passe) -Se o ficheiro não existir, crie-o com permissões de leitura apenas para o dono. - - - - + Error Erro - - An error occured while setting up the RPC port %i for listening: %s - Ocorreu um erro ao definir a porta de escuta %i do serviço RPC: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2509,10 +2934,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Se o ficheiro não existir, crie-o com permissões de leitura apenas para o dono. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Atenção: Por favor verifique que a data e hora do seu computador estão correctas. Se o seu relógio não estiver certo o Bitcoin não irá funcionar correctamente. - \ 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 6b8bbd3..13bd542 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -3,116 +3,155 @@ AboutDialog - - About Bitcoin - Despre Bitcoin + + About CasinoCoin + Despre CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> versiunea + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> versiunea - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + Copyright + + + + + The CasinoCoin developers + + AddressBookPage - + Address Book Listă de adrese - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Acestea sunt adresele dumneavoastră Bitcoin pentru a primi plăţi. Dacă doriţi, puteți da o adresa diferită fiecărui expeditor, pentru a putea ţine evidenţa plăţilor. - - - + Double-click to edit address or label Dublu-click pentru a edita adresa sau eticheta - + Create a new address Creaţi o adresă nouă - + Copy the currently selected address to the system clipboard Copiați adresa selectată în clipboard - + &New Address - + &Adresă nouă - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Acestea sunt adresele dumneavoastră CasinoCoin pentru a primi plăţi. Dacă doriţi, puteți da o adresa diferită fiecărui expeditor, pentru a putea ţine evidenţa plăţilor. + + + &Copy Address - + &Copiază adresa - + Show &QR Code + Arata codul QR + + + + Sign a message to prove you own a CasinoCoin address + Semneaza mesajul pentru a dovedi ca detii aceasta adresa Bitocin + + + + Sign &Message + Semneaza mesajul + + + + Delete the currently selected address from the list + Sterge adresele curent selectate din lista + + + + Export the data in the current tab to a file - - Sign a message to prove you own this address + + &Export - - &Sign Message - + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verifica mesajul pentru a te asigura ca a fost insemnat cu o adresa casinocoin specifica - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Ștergeți adresa selectată din listă. Doar adresele de trimitere pot fi șterse. + + &Verify Message + Verifica mesajele - + &Delete &Șterge - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Copiază &eticheta - + &Edit + &Editează + + + + Send &Coins - + Export Address Book Data Exportă Lista de adrese - + Comma separated file (*.csv) Fisier csv: valori separate prin virgulă (*.csv) - + Error exporting Eroare la exportare. - + Could not write to file %1. Eroare la scrierea în fişerul %1. @@ -120,17 +159,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Etichetă - + Address Adresă - + (no label) (fără etichetă) @@ -138,1426 +177,1661 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase Introduceți fraza de acces. - + New passphrase Frază de acces nouă - + Repeat new passphrase Repetaţi noua frază de acces - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Introduceţi noua parolă a portofelului electronic.<br/>Vă rugăm să folosiţi <b>minimum 10 caractere aleatoare</b>, sau <b>minimum 8 cuvinte</b>. - + Encrypt wallet Criptează portofelul - + This operation needs your wallet passphrase to unlock the wallet. Aceasta operație are nevoie de un portofel deblocat. - + Unlock wallet Deblochează portofelul - + This operation needs your wallet passphrase to decrypt the wallet. Această operaţiune necesită parola pentru decriptarea portofelului electronic. - + Decrypt wallet Decriptează portofelul. - + Change passphrase Schimbă fraza de acces - + Enter the old and new passphrase to the wallet. Introduceţi vechea parola a portofelului eletronic şi apoi pe cea nouă. - + Confirm wallet encryption Confirmă criptarea portofelului. - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ATENŢIE: Dacă pierdeţi parola portofelului electronic dupa criptare, <b>VEŢI PIERDE ÎNTREAGA SUMĂ DE BITCOIN ACUMULATĂ</b>! -Sunteţi sigur că doriţi să criptaţi portofelul electronic? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Atenție: Dacă pierdeţi parola portofelului electronic dupa criptare, <b>VEŢI PIERDE ÎNTREAGA SUMĂ DE CASINOCOIN ACUMULATĂ</b>! - - + + Are you sure you wish to encrypt your wallet? + Sunteţi sigur că doriţi să criptaţi portofelul electronic? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + Atentie! Caps Lock este pornit + + + + Wallet encrypted Portofel criptat - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin se va închide acum pentru a termina procesul de criptare. Amintiți-vă că criptarea portofelului dumneavoastră nu poate proteja în totalitate casinocoins dvs. de a fi furate de intentii rele. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed Criptarea portofelului a eșuat. - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Criptarea portofelului a eșuat din cauza unei erori interne. Portofelul tău nu a fost criptat. - - + + The supplied passphrases do not match. Fraza de acces introdusă nu se potrivește. - + Wallet unlock failed Deblocarea portofelului electronic a eşuat. - - - + + + The passphrase entered for the wallet decryption was incorrect. Parola introdusă pentru decriptarea portofelului electronic a fost incorectă. - + Wallet decryption failed Decriptarea portofelului electronic a eşuat. - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Parola portofelului electronic a fost schimbată. BitcoinGUI - - Bitcoin Wallet - Portofel electronic Bitcoin - - - + Sign &message... - + Semneaza &mesaj... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Se sincronizează cu reţeaua... - + &Overview &Detalii - + Show general overview of wallet Afişează detalii despre portofelul electronic - + &Transactions &Tranzacţii - + Browse transaction history Istoricul tranzacţiilor - - &Address Book - &Lista de adrese - - - + Edit the list of stored addresses and labels Editaţi lista de adrese şi etichete. - - &Receive coins - &Primiţi Bitcoin - - - + Show the list of addresses for receiving payments Lista de adrese pentru recepţionarea plăţilor - - &Send coins - &Trimiteţi Bitcoin - - - - Prove you control an address - - - - + E&xit - + Ieșire - + Quit application Părăsiţi aplicaţia - - &About %1 - + + Show information about CasinoCoin + Informaţii despre CasinoCoin - - Show information about Bitcoin - Informaţii despre Bitcoin - - - + About &Qt - + Despre &Qt - + Show information about Qt - + Informaţii despre Qt - + &Options... &Setări... - + &Encrypt Wallet... - + Criptează portofelul electronic... - + &Backup Wallet... - + &Backup portofelul electronic... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Schimbă parola... - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... + Importare blocks de pe disk... + + + + Reindexing blocks on disk... - - &Export... - &Exportă... + + Send coins to a CasinoCoin address + &Trimiteţi CasinoCoin către o anumită adresă - - Send coins to a Bitcoin address - + + Modify configuration options for CasinoCoin + Modifică setările pentru CasinoCoin - - Modify configuration options for Bitcoin - - - - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - Criptează şi decriptează portofelul electronic - - - + Backup wallet to another location - + Creaza copie de rezerva a portofelului intr-o locatie diferita - + Change the passphrase used for wallet encryption &Schimbă parola folosită pentru criptarea portofelului electronic - + &Debug window - + & Fereastra debug - + Open debugging and diagnostic console - + Deschide consola de debug si diagnosticare - + &Verify message... + Verifica mesajul + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Portofelul + + + + &Send - - Verify a message signature + + &Receive - + + &Addresses + + + + + &About CasinoCoin + &Despre CasinoCoin + + + + &Show / Hide + Arata/Ascunde + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Fişier - + &Settings &Setări - + &Help &Ajutor - + Tabs toolbar Bara de ferestre de lucru - - Actions toolbar - Bara de acţiuni - - - - + + [testnet] [testnet] - - - Bitcoin client + + CasinoCoin client + Client CasinoCoin + + + + %n active connection(s) to CasinoCoin network + %n active connections to CasinoCoin network%n active connections to CasinoCoin network%n active connections to CasinoCoin network + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. - - %n active connection(s) to Bitcoin network - %n active connections to Bitcoin network%n active connections to Bitcoin network%n active connections to Bitcoin network + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + - - Downloaded %1 blocks of transaction history. - S-au descărcat %1 blocuri din istoricul tranzaciilor. - - - - %n second(s) ago - %n seconds ago%n seconds ago%n seconds ago - - - - %n minute(s) ago - Acum %n minutAcum %n minuteAcum %n minute - - - - %n hour(s) ago - Acum %n orăAcum %n oreAcum %n ore - - - - %n day(s) ago - Acum %n ziAcum %n zileAcum %n zile + + %1 behind + - + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Actualizat - + Catching up... Se actualizează... - - Last received block was generated %1. - Ultimul bloc primit a fost generat %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Această tranzacţie depăşeşte limita. Puteţi iniţia tranzacţia platind un comision de %1, de care vor beneficia nodurile care procesează tranzacţia şi ajută la menţinerea reţelei. Acceptaţi plata comisionului? - - - + Confirm transaction fee - + Confirma taxa tranzactiei - + Sent transaction Tranzacţie expediată - + Incoming transaction Tranzacţie recepţionată - + Date: %1 Amount: %2 Type: %3 Address: %4 + Data: %1⏎ Suma: %2⏎ Tipul: %3⏎ Addresa: %4⏎ + + + + + URI handling - + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Portofelul electronic este <b>criptat</b> iar in momentul de faţă este <b>deblocat</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Portofelul electronic este <b>criptat</b> iar in momentul de faţă este <b>blocat</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Afişare - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Alege subdiviziunea folosită la afişarea interfeţei şi la trimiterea de bitcoin. - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Alerta retea EditAddressDialog - + Edit Address Editează adresa - + &Label &Eticheta - + The label associated with this address book entry Eticheta asociată cu această înregistrare în Lista de adrese - + &Address &Adresă - + The address associated with this address book entry. This can only be modified for sending addresses. Adresa asociată cu această înregistrare în Lista de adrese. Aceasta poate fi modificată doar pentru expediere. - + New receiving address Noua adresă de primire - + New sending address Noua adresă de trimitere - + Edit receiving address Editează adresa de primire - + Edit sending address Editează adresa de trimitere - + The entered address "%1" is already in the address book. Adresa introdusă "%1" se află deja în Lista de adrese. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Adresa introdusă "%1" nu este o adresă casinocoin valabilă. - + Could not unlock wallet. Portofelul electronic nu a putut fi deblocat . - + New key generation failed. New key generation failed. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + versiunea - + Usage: Uz: - - options - + + command-line options + command-line setări - + UI options - + UI setări - + Set language, for example "de_DE" (default: system locale) - + Seteaza limba, de exemplu: "de_DE" (initialt: system locale) - + Start minimized - + Incepe miniaturizare - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - Plăteşte comision pentru tranzacţie &f - - - - Main - Principal - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Alegeţi adresa din Listă - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Lipiţi adresa copiată in clipboard. - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduceţi o adresă Bitcoin (de exemplu: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - Mapeaza portul folosind &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Deschide automat în router portul aferent clientului Bitcoin. Funcţionează doar în cazul în care routerul e compatibil UPnP şi opţiunea e activată. - - - - &Connect through SOCKS4 proxy: - &Conectează prin proxy SOCKS4: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Conectare la reţeaua Bitcoin folosind un proxy SOCKS4 (de exemplu, când conexiunea se stabileşte prin reţeaua Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - Adresa de IP a proxy serverului (de exemplu: 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Portul pe care se concetează proxy serverul (de exemplu: 1234) + Afișează pe ecran splash la pornire (implicit: 1) OptionsDialog - + Options Setări + + + &Main + &Principal + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + Plăteşte comision pentru tranzacţie &f + + + + Automatically start CasinoCoin after logging in to the system. + Porneşte automat programul CasinoCoin la pornirea computerului. + + + + &Start CasinoCoin on system login + &S Porneşte CasinoCoin la pornirea sistemului + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + &Retea + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Deschide automat în router portul aferent clientului CasinoCoin. Funcţionează doar în cazul în care routerul e compatibil UPnP şi opţiunea e activată. + + + + Map port using &UPnP + Mapeaza portul folosind &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Conectare la reţeaua CasinoCoin folosind un proxy SOCKS (de exemplu, când conexiunea se stabileşte prin reţeaua Tor) + + + + &Connect through SOCKS proxy: + &Conectează prin proxy SOCKS: + + + + Proxy &IP: + Proxy &IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + Adresa de IP a proxy serverului (de exemplu: 127.0.0.1) + + + + &Port: + &Port: + + + + Port of the proxy (e.g. 9050) + Portul pe care se concetează proxy serverul (de exemplu: 9050) + + + + SOCKS &Version: + SOCKS &Versiune: + + + + SOCKS version of the proxy (e.g. 5) + Versiunea SOCKS a proxiului (ex. 5) + + + + &Window + &Fereastra + + + + Show only a tray icon after minimizing the window. + Afişează doar un icon in tray la ascunderea ferestrei + + + + &Minimize to the tray instead of the taskbar + &M Ascunde în tray în loc de taskbar + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Ascunde fereastra în locul părăsirii programului în momentul închiderii ferestrei. Când acestă opţiune e activă, aplicaţia se va opri doar în momentul selectării comenzii Quit din menu. + + + + M&inimize on close + &i Ascunde fereastra în locul închiderii programului + + + + &Display + &Afişare + + + + User Interface &language: + Interfata & limba userului + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Limba interfeței utilizatorului poate fi setat aici. Această setare va avea efect după repornirea CasinoCoin. + + + + &Unit to show amounts in: + &Unitatea de măsură pentru afişarea sumelor: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Alege subdiviziunea folosită la afişarea interfeţei şi la trimiterea de casinocoin. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Vezi dacă adresele CasinoCoin sunt în lista de tranzacție sau nu + + + + &Display addresses in transaction list + &Afişează adresele în lista de tranzacţii + + + + &OK + & OK + + + + &Cancel + & Renunta + + + + &Apply + Aplica + + + + default + Initial + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Atentie! + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + Adresa casinocoin pe care a-ti specificat-o este invalida + OverviewPage - + Form Form - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Informațiile afișate pot fi expirate. Portofelul tău se sincronizează automat cu rețeaua CasinoCoin după ce o conexiune este stabilita, dar acest proces nu a fost finalizat încă. - + Balance: Balanţă: - - Number of transactions: - Număr total de tranzacţii: - - - + Unconfirmed: Neconfirmat: - + Wallet - + Portofelul - + + Immature: + Nematurizat: + + + + Mined balance that has not yet matured + Balanta minata care nu s-a maturizat inca + + + <b>Recent transactions</b> <b>Ultimele tranzacţii</b> - + Your current balance Soldul contul - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Totalul tranzacţiilor care aşteaptă să fie confirmate şi care nu sunt încă luate în calcul la afişarea soldului contului. - - Total number of transactions in wallet - Numărul total de tranzacţii din portofelul electronic - - - - + + out of sync + Nu este sincronizat + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - + Dialogul codului QR - - QR Code - - - - + Request Payment - + Cerere de plata - + Amount: - + Sumă: - - BTC - - - - + Label: - + Etichetă: - + Message: Mesaj: - + &Save As... - + Salvare ca... - + Error encoding URI into QR Code. - + Eroare la incercarea codarii URl-ului in cod QR - + + The entered amount is invalid, please check. + Suma introdusa nu este valida, verifica suma. + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + Salveaza codul QR - + PNG Images (*.png) - + Imagini de tip PNG (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Numaele clientului - - - - - - - - - + + + + + + + + + + N/A - + N/A - + Client version - + Versiunea clientului - + &Information - + & Informatie - - Client - + + Using OpenSSL version + Foloseste versiunea OpenSSL - + Startup time - + Data pornirii - + Network - + Retea - + Number of connections - + Numarul de conexiuni - + On testnet - + Pe testnet - + Block chain - + Lant bloc - + Current number of blocks - + Numarul curent de blockuri - + Estimated total blocks - + Estimarea totala a blocks - + Last block time - + Ultimul block a fost gasit la: - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + &Deschide - + + Command-line options + Command-line setări + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Arata mesajul de ajutor CasinoCoin-QT pentru a obtine o lista cu posibilele optiuni ale comenzilor CasinoCoin + + + + &Show + & Arata + + + &Console - + &Consola - + Build date - + Construit la data: - + + CasinoCoin - Debug window + CasinoCoin-Fereastra pentru debug + + + + CasinoCoin Core + CasinoCoin Core + + + + Debug log file + Loguri debug + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Deschide logurile debug din directorul curent. Aceasta poate dura cateva secunde pentru fisierele mai mari + + + Clear console - + Curata consola - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Bun venit la consola casinocoin RPC - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Foloseste sagetile sus si jos pentru a naviga in istoric si <b>Ctrl-L</b> pentru a curata. - + Type <b>help</b> for an overview of available commands. - + Scrie <b>help</b> pentru a vedea comenzile disponibile SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Trimite Bitcoin + Trimite CasinoCoin - + Send to multiple recipients at once Trimite simultan către mai mulţi destinatari - - &Add Recipient - + + Add &Recipient + &Adaugă destinatar - + Remove all transaction fields - + Sterge toate spatiile de tranzactie - + Clear &All - + Şterge &tot - + Balance: Balanţă: - + 123.456 BTC 123.456 BTC - + Confirm the send action Confirmă operaţiunea de trimitere - - &Send + + S&end &S Trimite - + <b>%1</b> to %2 (%3) <b>%1</b> la %2 (%3) - + Confirm send coins - Confirmaţi trimiterea de bitcoin + Confirmaţi trimiterea de casinocoin - + Are you sure you want to send %1? Sunteţi sigur că doriţi să trimiteţi %1? - + and şi - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Adresa destinatarului nu este validă, vă rugăm să o verificaţi. - + The amount to pay must be larger than 0. Suma de plată trebuie să fie mai mare decât 0. - + The amount exceeds your balance. - + Suma depăşeşte soldul contului. - + The total exceeds your balance when the %1 transaction fee is included. - + Total depăşeşte soldul contului in cazul plăţii comisionului de %1. - + Duplicate address found, can only send to each address once per send operation. + S-a descoperit o adresă care figurează de două ori. Expedierea se poate realiza către fiecare adresă doar o singură dată pe operaţiune. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Eroare: Tranyacţia a fost respinsă. Acesta poate fi rezultatul cheltuirii prealabile a unei sume de casinocoin din portofelul electronic, ca în cazul folosirii unei copii a fisierului wallet.dat, în care s-au efectuat tranzacţii neînregistrate în fisierul curent. SendCoinsEntry - + Form Form - + A&mount: Su&mă : - + Pay &To: Plăteşte Că&tre: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Adaugă o etichetă acestei adrese pentru a o trece în Lista de adrese - + &Label: &L Etichetă: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresa către care se va face plata (de exemplu: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book - + Alegeţi adresa din Listă - + Alt+A Alt+A - + Paste address from clipboard Lipiţi adresa copiată in clipboard. - + Alt+P Alt+P - + Remove this recipient Şterge destinatarul - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Introduceţi o adresă Bitcoin (de exemplu: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduceţi o adresă CasinoCoin (de exemplu: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Semnatura- Semneaza/verifica un mesaj + + + + &Sign Message + Semneaza Mesajul + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduceţi o adresă CasinoCoin (de exemplu: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Alegeţi adresa din Listă + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Lipiţi adresa copiată in clipboard. + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Introduce mesajul pe care vrei sa il semnezi, aici. + + + + Signature + + + + + Copy the current signature to the system clipboard + Copiaza semnatura curenta in clipboard-ul sistemului + + + + Sign the message to prove you own this CasinoCoin address + Semneaza mesajul pentru a dovedi ca detii acesta adresa CasinoCoin + + + + Sign &Message + + + + + Reset all sign message fields + Reseteaza toate spatiile mesajelor semnate. + + + + + Clear &All + Şterge &tot + + + + &Verify Message + Verifica mesajul + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduceţi o adresă CasinoCoin (de exemplu: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verifica mesajul pentru a fi sigur ca a fost semnat cu adresa CasinoCoin specifica + + + + Verify &Message + + + + + Reset all verify message fields + Reseteaza toate spatiile mesajelor semnate. + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Introduceţi o adresă CasinoCoin (de exemplu: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Click "Semneaza msajul" pentru a genera semnatura + + + + Enter CasinoCoin signature + Introduce semnatura bitocin + + + + + The entered address is invalid. + Adresa introdusa nu este valida + + + + + + + Please check the address and try again. + Te rugam verifica adresa si introduce-o din nou + + + + + The entered address does not refer to a key. + Adresa introdusa nu se refera la o cheie. + + + + Wallet unlock was cancelled. + Blocarea portofelului a fost intrerupta + + + + Private key for the entered address is not available. + Cheia privata pentru adresa introdusa nu este valida. + + + + Message signing failed. + Semnarea mesajului a esuat + + + + Message signed. + Mesaj Semnat! + + + + The signature could not be decoded. + Aceasta semnatura nu a putut fi decodata + + + + + Please check the signature and try again. + Verifica semnatura si incearca din nou + + + + The signature did not match the message digest. + Semnatura nu seamana! + + + + Message verification failed. + Verificarea mesajului a esuat + + + + Message verified. + Mesaj verificat + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Deschis pentru %1 blocuri - - - + Open until %1 Deschis până la %1 - - %1/offline? - %1/offline? + + %1/offline + - + %1/unconfirmed %1/neconfirmat - + %1 confirmations %1 confirmări - - <b>Status:</b> - <b>Stare:</b> + + Status + Stare + + + + , broadcast through %n node(s) + - + + Date + Data + + + + Source + Sursa + + + + Generated + Generat + + + + + From + De la + + + + + + To + Către + + + + + own address + Adresa posedata + + + + label + etichetă + + + + + + + + Credit + Credit + + + + matures in %n more block(s) + + + + + not accepted + nu este acceptat + + + + + + + Debit + Debit + + + + Transaction fee + Comisionul tranzacţiei + + + + Net amount + Suma netă + + + + Message + Mesaj + + + + Comment + Comentarii + + + + Transaction ID + ID-ul tranzactiei + + + + Generated coins must mature 120 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. + Monedele casinocoin generate se pot cheltui dupa parcurgerea a 120 de blocuri. După ce a fost generat, s-a propagat în reţea, urmând să fie adăugat lanţului de blocuri. Dacă nu poate fi inclus in lanţ, starea sa va deveni "neacceptat" si nu va putea fi folosit la tranzacţii. Acest fenomen se întâmplă atunci cand un alt nod a generat un bloc la o diferenţa de câteva secunde. + + + + Debug information + Informatii pentru debug + + + + Transaction + Tranzacţie + + + + Inputs + Intrari + + + + Amount + Sumă + + + + true + Adevarat! + + + + false + Fals! + + + , has not been successfully broadcast yet , nu s-a propagat încă - - - , broadcast through %1 node - , se propagă prin %1 nod + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , se propagă prin %1 noduri - - - - <b>Date:</b> - <b>Data:</b> - - - - <b>Source:</b> Generated<br> - <b>Sursă:</b> Generat<br> - - - - - <b>From:</b> - <b>De la:</b> - - - + unknown necunoscut - - - - - <b>To:</b> - <b>Către:</b> - - - - (yours, label: - (propriu, etichetă: - - - - (yours) - (propriu) - - - - - - - <b>Credit:</b> - <b>Credit:</b> - - - - (%1 matures in %2 more blocks) - (%1 se definitivează peste %2 blocuri) - - - - (not accepted) - (nu este acceptat) - - - - - - <b>Debit:</b> - <b>Debit:</b> - - - - <b>Transaction fee:</b> - <b>Comisionul tranzacţiei:</b> - - - - <b>Net amount:</b> - <b>Suma netă:</b> - - - - Message: - Mesaj: - - - - Comment: - Comentarii: - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Monedele bitcoin generate se pot cheltui dupa parcurgerea a 120 de blocuri. După ce a fost generat, s-a propagat în reţea, urmând să fie adăugat lanţului de blocuri. Dacă nu poate fi inclus in lanţ, starea sa va deveni "neacceptat" si nu va putea fi folosit la tranzacţii. Acest fenomen se întâmplă atunci cand un alt nod a generat un bloc la o diferenţa de câteva secunde. - TransactionDescDialog - + Transaction details Detaliile tranzacţiei - + This pane shows a detailed description of the transaction Afişează detalii despre tranzacţie @@ -1565,117 +1839,117 @@ Address: %4 TransactionTableModel - + Date Data - + Type Tipul - + Address Adresa - + Amount Cantitate - - Open for %n block(s) - Deschis pentru for %n blocDeschis pentru %n blocuriDeschis pentru %n blocuri + + Open for %n more block(s) + - + Open until %1 Deschis până la %1 - + Offline (%1 confirmations) Neconectat (%1 confirmări) - + Unconfirmed (%1 of %2 confirmations) Neconfirmat (%1 din %2 confirmări) - + Confirmed (%1 confirmations) Confirmat (%1 confirmări) - - Mined balance will be available in %n more blocks - Soldul de bitcoin produs va fi disponibil după încă %n blocSoldul de bitcoin produs va fi disponibil după încă %n blocuriSoldul de bitcoin produs va fi disponibil după încă %n blocuri + + Mined balance will be available when it matures in %n more block(s) + - + This block was not received by any other nodes and will probably not be accepted! Blocul nu a fost recepţionat de niciun alt nod şi e probabil că nu va fi acceptat. - + Generated but not accepted Generat, dar neacceptat - + Received with Recepţionat cu - + Received from - + Primit de la: - + Sent to Trimis către - + Payment to yourself Plată către un cont propriu - + Mined Produs - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. Starea tranzacţiei. Treceţi cu mouse-ul peste acest câmp pentru afişarea numărului de confirmări. - + Date and time that the transaction was received. Data şi ora la care a fost recepţionată tranzacţia. - + Type of transaction. Tipul tranzacţiei. - + Destination address of transaction. Adresa de destinaţie a tranzacţiei. - + Amount removed from or added to balance. Suma extrasă sau adăugată la sold. @@ -1683,818 +1957,966 @@ Address: %4 TransactionView - - + + All Toate - + Today Astăzi - + This week Săptămâna aceasta - + This month Luna aceasta - + Last month Luna trecută - + This year Anul acesta - + Range... Între... - + Received with Recepţionat cu... - + Sent to Trimis către - + To yourself Către propriul cont - + Mined Produs - + Other Altele - + Enter address or label to search Introduceţi adresa sau eticheta pentru căutare - + Min amount Cantitatea produsă - + Copy address Copiază adresa - + Copy label Copiază eticheta - + Copy amount + Copiază sumă + + + + Copy transaction ID - + Edit label Editează eticheta - + Show transaction details - + Arata detaliile tranzactiei - + Export Transaction Data Exportă tranzacţiile - + Comma separated file (*.csv) Fişier text cu valori separate prin virgulă (*.csv) - + Confirmed Confirmat - + Date Data - + Type Tipul - + Label Etichetă - + Address Adresă - + Amount Sumă - + ID ID - + Error exporting Eroare în timpul exportului - + Could not write to file %1. Fisierul %1 nu a putut fi accesat pentru scriere. - + Range: Interval: - + to către - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Copiați adresa selectată în clipboard - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Se expediază... + + Send Coins + Trimite CasinoCoin - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - &M Ascunde în tray în loc de taskbar - - - - Show only a tray icon after minimizing the window - Afişează doar un icon in tray la ascunderea ferestrei - - - - M&inimize on close + + Export the data in the current tab to a file - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Ascunde fereastra în locul părăsirii programului în momentul închiderii ferestrei. Când acestă opţiune e activă, aplicaţia se va opri doar în momentul selectării comenzii Quit din menu. + + Backup Wallet + + + + + Wallet Data (*.dat) + Date portofel (*.dat) + + + + Backup Failed + Copia de rezerva a esuat + + + + There was an error trying to save the wallet data to the new location. + A apărut o eroare la încercarea de a salva datele din portofel intr-o noua locație. + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - versiunea Bitcoin + + CasinoCoin version + versiunea CasinoCoin - + Usage: Uz: - - Send command to -server or bitcoind - Trimite comanda la -server sau bitcoind + + Send command to -server or casinocoind + Trimite comanda la -server sau casinocoind - + List commands Listă de comenzi - + Get help for a command Ajutor pentru o comandă - + Options: Setări: - - Specify configuration file (default: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Specifica-ți configurația fisierului (in mod normal: casinocoin.conf) + + + + Specify pid file (default: casinocoind.pid) - - Specify pid file (default: bitcoind.pid) - - - - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Specifica datele directorului - + Set database cache size in megabytes (default: 25) - + Seteaza marimea cache a bazei de date in MB (initial: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Lista a conectiunile in <port> (initial: 47950 sau testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + Se menține la cele mai multe conexiuni <n> cu colegii (implicit: 125) - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Conecteaza-te la nod pentru a optine adresa peer, si deconecteaza-te - + Specify your own public address - + Specifica adresa ta publica - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Prag pentru deconectarea colegii funcționează corect (implicit: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Numărul de secunde pentru a păstra colegii funcționează corect la reconectare (implicit: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - - - - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Se accepta command line si comenzi JSON-RPC - + Run in the background as a daemon and accept commands - + Ruleaza în background ca un demon și accepta comenzi. - + Use the test network - + Utilizeaza test de retea - - Output extra debugging information - + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accepta conexiuni de la straini (initial: 1 if no -proxy or -connect) + - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - Bitcoin - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - Încarc adrese... - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Eroare: Tranyacţia nu a putut fi iniţiată - - - - Sending... - Transmitere... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Eroare: Tranyacţia a fost respinsă. Acesta poate fi rezultatul cheltuirii prealabile a unei sume de bitcoin din portofelul electronic, ca în cazul folosirii unei copii a fisierului wallet.dat, în care s-au efectuat tranzacţii neînregistrate în fisierul curent. - - - - Invalid amount - - - - - Insufficient funds - Fonduri insuficiente - - - - Loading block index... - Încarc indice bloc... - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - Încarc portofel... - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - Rescanez... - - - - Done loading - Încărcare terminată - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Seteaza marimea maxima a tranzactie mare/mica in bytes (initial:27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + Optiuni creare block + + + + Connect only to the specified node(s) + Conecteaza-te doar la nod(urile) specifice + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + Descopera propria ta adresa IP (intial: 1) + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + Copie de ieșire de depanare cu timestamp + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Optiuni SSl (vezi CasinoCoin wiki pentru intructiunile de instalare) + + + + Select the version of socks proxy to use (4-5, default: 5) + Selecteaza versiunea socks-ului pe care vrei sa il folosesti (4-5, initial: 5) + + + + Send trace/debug info to console instead of debug.log file + Trimite urmări / debug info la consola loc de debug.log fișier + + + + Send trace/debug info to debugger + Trimite urmări / debug info la depanatorul + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Foloseste UPnP pentru a vedea porturile (initial: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Foloseste UPnP pentru a vedea porturile (initial: 1 cand listezi) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + Username pentru conectiunile JSON-RPC + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Parola pentru conectiunile JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Permiteti conectiunile JSON-RPC de la o adresa IP specifica. + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Trimite comenzi la nod, ruland pe ip-ul (initial: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Executa comanda cand cel mai bun block se schimba (%s in cmd se inlocuieste cu block hash) + + + + Upgrade wallet to latest format + Actualizeaza portofelul la ultimul format + + + + Set key pool size to <n> (default: 100) + Setarea marimii cheii bezinului la <n>(initial 100) + + + + Rescan the block chain for missing wallet transactions + Rescanare lanțul de bloc pentru tranzacțiile portofel lipsă + + + + Use OpenSSL (https) for JSON-RPC connections + Foloseste Open SSL(https) pentru coneciunile JSON-RPC + + + + Server certificate file (default: server.cert) + Certificatul serverulu (initial: server.cert) + + + + Server private key (default: server.pem) + Cheia privata a serverului ( initial: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Accepta cifruri (initial: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Acest mesaj de ajutor. + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Nu se poate lega %s cu acest calculator (retunare eroare legatura %d, %s) + + + + + + Connect through socks proxy + Conectează prin proxy SOCKS + + + + Allow DNS lookups for -addnode, -seednode and -connect + Permite DNS-ului sa se uite dupa -addnode, -seednode si -connect + + + + Loading addresses... + Încarc adrese... + + + + Error loading wallet.dat: Wallet corrupted + Eroare incarcand wallet.dat: Portofel corupt + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Eroare incarcare wallet.dat: Portofelul are nevoie de o versiune CasinoCoin mai noua + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Portofelul trebuie rescris: restarteaza aplicatia casinocoin pentru a face asta. + + + + Error loading wallet.dat + Eroare incarcand wallet.dat + + + + Invalid -proxy address: '%s' + Adresa proxy invalida: '%s' + + + + Unknown network specified in -onlynet: '%s' + Retea specificata necunoscuta -onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + Necunoscut -socks proxy version requested: %i + + + + Cannot resolve -bind address: '%s' + Nu se poate rezolca -bind address: '%s' + + + + Cannot resolve -externalip address: '%s' + Nu se poate rezolva -externalip address: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Suma invalida pentru -paytxfee=<amount>: '%s' + + + + Invalid amount + Suma invalida + + + + Insufficient funds + Fonduri insuficiente + + + + Loading block index... + Încarc indice bloc... + + + + Add a node to connect to and attempt to keep the connection open + Add a node to connect to and attempt to keep the connection open +details suggestions history + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Imposibilitatea de a lega la% s pe acest computer. CasinoCoin este, probabil, deja în execuție. + + + + Fee per KB to add to transactions you send + Taxa pe kb pentru a adauga tranzactii trimise + + + + Loading wallet... + Încarc portofel... + + + + Cannot downgrade wallet + Nu se poate face downgrade la portofel + + + + Cannot write default address + Nu se poate scrie adresa initiala + + + + Rescanning... + Rescanez... + + + + Done loading + Încărcare terminată + + + + To use the %s option + Pentru a folosii optiunea %s + + + Error - + Eroare - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index f4e3c8c..d92fd50 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - О Bitcoin + + About CasinoCoin + &О CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> версия + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> версия - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Все права защищены © 2009-2012 Разработчики Bitcoin - + Это экспериментальная программа. Распространяется на правах лицензии MIT/X11, см. файл license.txt или http://www.opensource.org/licenses/mit-license.php. Этот продукт включает ПО, разработанное OpenSSL Project для использования в OpenSSL Toolkit (http://www.openssl.org/) и криптографическое ПО, написанное Eric Young (eay@cryptsoft.com) и ПО для работы с UPnP, написанное Thomas Bernard. + + + Copyright + Все права защищены + + + + The CasinoCoin developers + Разработчики CasinoCoin + AddressBookPage - + Address Book - Адресная книга + &Адресная книга - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Здесь перечислены Ваши адреса для получения платежей. Вы можете использовать их для того, чтобы давать разным людям разные адреса и, таким образом, иметь возможность отслеживать, кто и сколько Вам платил, а также поддерживать бо́льшую анонимность. - - - + Double-click to edit address or label - Для того, чтобы изменить адрес или метку давжды кликните по изменяемому объекту + Для того, чтобы изменить адрес или метку, дважды кликните по изменяемому объекту - + Create a new address Создать новый адрес - + Copy the currently selected address to the system clipboard Копировать текущий выделенный адрес в буфер обмена - + &New Address &Новый адрес - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Это Ваши адреса для получения платежей. Вы можете дать разные адреса отправителям, чтобы отслеживать, кто именно вам платит. + + + &Copy Address &Копировать адрес - + Show &QR Code Показать &QR код - - Sign a message to prove you own this address - Подпишите сообщение для доказательства + + Sign a message to prove you own a CasinoCoin address + Подписать сообщение, чтобы доказать владение адресом CasinoCoin - - &Sign Message + + Sign &Message &Подписать сообщение - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Удалить выделенный адрес из списка (могут быть удалены только записи из адресной книги). + + Delete the currently selected address from the list + Удалить выбранный адрес из списка - + + Export the data in the current tab to a file + Экспортировать данные из вкладки в файл + + + + &Export + &Экспорт + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Проверить сообщение, чтобы убедиться, что оно было подписано указанным адресом CasinoCoin + + + + &Verify Message + &Проверить сообщение + + + &Delete &Удалить - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Ваши адреса для получения средств. Совет: проверьте сумму и адрес назначения перед переводом. + + + Copy &Label Копировать &метку - + &Edit &Правка - + + Send &Coins + &Отправить монеты + + + Export Address Book Data Экспортировать адресную книгу - + Comma separated file (*.csv) Текст, разделённый запятыми (*.csv) - + Error exporting Ошибка экспорта - + Could not write to file %1. Невозможно записать в файл %1. @@ -126,17 +164,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Метка - + Address Адрес - + (no label) [нет метки] @@ -144,432 +182,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog Диалог ввода пароля - + Enter passphrase Введите пароль - + New passphrase Новый пароль - + Repeat new passphrase Повторите новый пароль - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Введите новый пароль для бумажника. <br/> Пожалуйста, используйте фразы из <b>10 или более случайных символов,</b> или <b>восьми и более слов.</b> - + Encrypt wallet Зашифровать бумажник - + This operation needs your wallet passphrase to unlock the wallet. Для выполнения операции требуется пароль вашего бумажника. - + Unlock wallet Разблокировать бумажник - + This operation needs your wallet passphrase to decrypt the wallet. Для выполнения операции требуется пароль вашего бумажника. - + Decrypt wallet Расшифровать бумажник - + Change passphrase Сменить пароль - + Enter the old and new passphrase to the wallet. Введите старый и новый пароль для бумажника. - + Confirm wallet encryption Подтвердите шифрование бумажника - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - ВНИМАНИЕ: Если вы зашифруете бумажник и потеряете свой ​​пароль, вы <b>ПОТЕРЯЕТЕ ВСЕ ВАШИ БИТКОИНЫ!</b> -Вы действительно хотите зашифровать ваш бумажник? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Внимание: если вы зашифруете бумажник и потеряете пароль, вы <b>ПОТЕРЯЕТЕ ВСЕ ВАШИ CASINOCOIN</b>! - - + + Are you sure you wish to encrypt your wallet? + Вы уверены, что хотите зашифровать ваш бумажник? + + + + 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. + ВАЖНО: все предыдущие резервные копии вашего кошелька должны быть заменены новым зашифрованным файлом. В целях безопасности предыдущие резервные копии нешифрованного кошелька станут бесполезны, как только вы начнёте использовать новый шифрованный кошелёк. + + + + + Warning: The Caps Lock key is on! + Внимание: Caps Lock включен! + + + + Wallet encrypted Бумажник зашифрован - - Bitcoin 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. - Сейчас программа закроется для завершения процесса шифрования. Помните, что шифрование вашего бумажника не может полностью защитить ваши биткоины от кражи с помощью инфицирования вашего компьютера вредоносным ПО. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + Сейчас программа закроется для завершения процесса шифрования. Помните, что шифрование вашего бумажника не может полностью защитить ваши CasinoCoin от кражи с помощью инфицирования вашего компьютера вредоносным ПО. - - - Warning: The Caps Lock key is on. - Внимание: Caps Lock включен. - - - - - - + + + + Wallet encryption failed Не удалось зашифровать бумажник - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Шифрование бумажника не удалось из-за внутренней ошибки. Ваш бумажник не был зашифрован. - - + + The supplied passphrases do not match. Введённые пароли не совпадают. - + Wallet unlock failed Разблокировка бумажника не удалась - - - + + + The passphrase entered for the wallet decryption was incorrect. Указанный пароль не подходит. - + Wallet decryption failed Расшифрование бумажника не удалось - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Пароль бумажника успешно изменён. BitcoinGUI - - Bitcoin Wallet - Bitcoin-бумажник - - - + Sign &message... - &Подписать сообщение + &Подписать сообщение... - - Show/Hide &Bitcoin - Показать/Скрыть &Bitcoin - - - + Synchronizing with network... Синхронизация с сетью... - + &Overview О&бзор - + Show general overview of wallet Показать общий обзор действий с бумажником - + &Transactions &Транзакции - + Browse transaction history Показать историю транзакций - - &Address Book - &Адресная книга - - - + Edit the list of stored addresses and labels Изменить список сохранённых адресов и меток к ним - - &Receive coins - &Получение монет - - - + Show the list of addresses for receiving payments Показать список адресов для получения платежей - - &Send coins - Отп&равка монет - - - - Prove you control an address - Доказать, что вы владеете адресом - - - + E&xit В&ыход - + Quit application Закрыть приложение - - &About %1 - &О %1 + + Show information about CasinoCoin + Показать информацию о CasinoCoin'е - - Show information about Bitcoin - Показать информацию о Bitcoin'е - - - + About &Qt О &Qt - + Show information about Qt Показать информацию о Qt - + &Options... Оп&ции... - + &Encrypt Wallet... - &Зашифровать бумажник + &Зашифровать бумажник... - + &Backup Wallet... - &Сделать резервную копию бумажника + &Сделать резервную копию бумажника... - + &Change Passphrase... - &Изменить пароль - - - - ~%n block(s) remaining - остался ~%n блокосталось ~%n блоковосталось ~%n блоков + &Изменить пароль... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Загружено %1 из %2 блоков истории операций (%3% завершено). + + Importing blocks from disk... + Импортируются блоки с диска... - - &Export... - &Экспорт... + + Reindexing blocks on disk... + Идёт переиндексация блоков на диске... - - Send coins to a Bitcoin address - Отправить монеты на указанный адрес Bitcoin + + Send coins to a CasinoCoin address + Отправить монеты на указанный адрес CasinoCoin - - Modify configuration options for Bitcoin - Изменить параметры конфигурации Bitcoin + + Modify configuration options for CasinoCoin + Изменить параметры конфигурации CasinoCoin - - Show or hide the Bitcoin window - Показать или скрыть окно Bitcoin - - - - Export the data in the current tab to a file - Экспортировать данные из вкладки в файл - - - - Encrypt or decrypt wallet - Зашифровать или расшифровать бумажник - - - + Backup wallet to another location Сделать резервную копию бумажника в другом месте - + Change the passphrase used for wallet encryption Изменить пароль шифрования бумажника - + &Debug window &Окно отладки - + Open debugging and diagnostic console Открыть консоль отладки и диагностики - + &Verify message... &Проверить сообщение... - - Verify a message signature - Проверить подпись сообщения + + + CasinoCoin + CasinoCoin - + + Wallet + Бумажник + + + + &Send + &Отправить + + + + &Receive + &Получить + + + + &Addresses + &Адреса + + + + &About CasinoCoin + &О CasinoCoin + + + + &Show / Hide + &Показать / Скрыть + + + + Show or hide the main Window + Показать или скрыть главное окно + + + + Encrypt the private keys that belong to your wallet + Зашифровать приватные ключи, принадлежащие вашему бумажнику + + + + Sign messages with your CasinoCoin addresses to prove you own them + Подписать сообщения вашим адресом CasinoCoin, чтобы доказать, что вы им владеете + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Проверить сообщения, чтобы удостовериться, что они были подписаны определённым адресом CasinoCoin + + + &File &Файл - + &Settings &Настройки - + &Help &Помощь - + Tabs toolbar Панель вкладок - - Actions toolbar - Панель действий - - - - + + [testnet] [тестовая сеть] - - - Bitcoin client - Bitcoin клиент + + CasinoCoin client + CasinoCoin клиент - - %n active connection(s) to Bitcoin network + + %n active connection(s) to CasinoCoin network %n активное соединение с сетью%n активных соединений с сетью%n активных соединений с сетью - - Downloaded %1 blocks of transaction history. - Загружено %1 блоков истории транзакций. - - - - %n second(s) ago - %n секунду назад%n секунды назад%n секунд назад - - - - %n minute(s) ago - %n минуту назад%n минуты назад%n минут назад - - - - %n hour(s) ago - %n час назад%n часа назад%n часов назад - - - - %n day(s) ago - %n день назад%n дня назад%n дней назад + + No block source available... + Источник блоков недоступен... - + + Processed %1 of %2 (estimated) blocks of transaction history. + Обработано %1 из %2 (примерно) блоков истории транзакций. + + + + Processed %1 blocks of transaction history. + Обработано %1 блоков истории транзакций. + + + + %n hour(s) + %n час%n часа%n часов + + + + %n day(s) + %n день%n дня%n дней + + + + %n week(s) + %n неделя%n недели%n недель + + + + %1 behind + %1 позади + + + + Last received block was generated %1 ago. + Последний полученный блок был сгенерирован %1 назад. + + + + Transactions after this will not yet be visible. + Транзакции после этой пока не будут видны. + + + + Error + Ошибка + + + + Warning + Внимание + + + + Information + Информация + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Транзакция превышает максимальный размер. Вы можете провести её, заплатив комиссию %1, которая достанется узлам, обрабатывающим эту транзакцию, и поможет работе сети. Вы действительно хотите заплатить комиссию? + + + Up to date - Синхронизированно + Синхронизировано - + Catching up... Синхронизируется... - - Last received block was generated %1. - Последний полученный блок был сгенерирован %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Данная транзакция превышает предельно допустимый размер. Но Вы можете всё равно совершить её, добавив комиссию в %1, которая отправится тем узлам, которые обработают Вашу транзакцию, и поможет поддержать сеть. Вы хотите добавить комиссию? - - - + Confirm transaction fee Подтвердите комиссию - + Sent transaction Исходящая транзакция - + Incoming transaction Входящая транзакция - + Date: %1 Amount: %2 Type: %3 @@ -582,538 +648,485 @@ Address: %4 - + + + URI handling + Обработка URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + Не удалось обработать URI! Это может быть связано с неверным адресом CasinoCoin или неправильными параметрами URI. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Бумажник <b>зашифрован</b> и в настоящее время <b>разблокирован</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Бумажник <b>зашифрован</b> и в настоящее время <b>заблокирован</b> - - Backup Wallet - Сделать резервную копию бумажника - - - - Wallet Data (*.dat) - Данные бумажника (*.dat) - - - - Backup Failed - Резервное копирование не удалось - - - - There was an error trying to save the wallet data to the new location. - При попытке сохранения данных бумажника в новое место произошла ошибка. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Обнаружена неисправимая ошибка. Bitcoin не может продолжать безопасную работу и будет закрыт. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Произошла неисправимая ошибка. CasinoCoin не может безопасно продолжать работу и будет закрыт. ClientModel - + Network Alert Сетевая Тревога - - DisplayOptionsPage - - - Display - Отображение - - - - default - по умолчанию - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - Здесь можно выбрать язык интерфейса. Настройки вступят в силу после перезапуска Bitcoin. - - - - User Interface &Language: - &Язык интерфейса - - - - &Unit to show amounts in: - &Отображать суммы в единицах: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Единица измерения количества монет при отображении и при отправке - - - - &Display addresses in transaction list - &Показывать адреса в списке транзакций - - - - Whether to show Bitcoin addresses in the transaction list - Показывать ли адреса Bitcoin в списке транзакций - - - - Warning - Внимание - - - - This setting will take effect after restarting Bitcoin. - Эта настройка вступит в силу после перезапуска Bitcoin - - EditAddressDialog - + Edit Address Изменить адрес - + &Label &Метка - + The label associated with this address book entry Метка, связанная с данной записью - + &Address &Адрес - + The address associated with this address book entry. This can only be modified for sending addresses. Адрес, связанный с данной записью. - + New receiving address Новый адрес для получения - + New sending address Новый адрес для отправки - + Edit receiving address Изменение адреса для получения - + Edit sending address Изменение адреса для отправки - + The entered address "%1" is already in the address book. Введённый адрес «%1» уже находится в адресной книге. - - The entered address "%1" is not a valid Bitcoin address. - Введённый адрес "%1" не является правильным Bitcoin-адресом. + + The entered address "%1" is not a valid CasinoCoin address. + Введённый адрес "%1" не является правильным CasinoCoin-адресом. - + Could not unlock wallet. Не удается разблокировать бумажник. - + New key generation failed. Генерация нового ключа не удалась. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version версия - + Usage: Использование: - - options - опции + + command-line options + параметры командной строки - + UI options Опции интерфейса - + Set language, for example "de_DE" (default: system locale) Выберите язык, например "de_DE" (по умолчанию: как в системе) - + Start minimized Запускать свёрнутым - + Show splash screen on startup (default: 1) Показывать сплэш при запуске (по умолчанию: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Отключить базы данных блоков и адресов при выходе. Это означает, что их можно будет переместить в другой каталог данных, но завершение работы будет медленнее. Бумажник всегда отключается. + + Options + Опции - + + &Main + &Главная + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Необязательная комиссия за каждый КБ транзакции, которая ускоряет обработку Ваших транзакций. Большинство транзакций занимают 1КБ. + + + Pay transaction &fee - Добавлять ко&миссию + Заплатить ко&миссию - - Main - Основное + + Automatically start CasinoCoin after logging in to the system. + Автоматически запускать CasinoCoin после входа в систему - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Опциональная комиссия за каждый КБ транзакции, которая позволяет быть уверенным, что Ваша транзакция будет обработана быстро. Большинство транзакций занимают 1КБ. Рекомендуется комиссия 0.01. + + &Start CasinoCoin on system login + &Запускать CasinoCoin при входе в систему - - &Start Bitcoin on system login - &Запускать Bitcoin при входе в систему + + Reset all client options to default. + Сбросить все опции клиента на значения по умолчанию. - - Automatically start Bitcoin after logging in to the system - Автоматически запускать Bitcoin после входа в систему + + &Reset Options + &Сбросить опции - - &Detach databases at shutdown - &Отключать базы данных при выходе - - - - MessagePage - - - Sign Message - Подписать сообщение + + &Network + &Сеть - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Вы можете подписывать сообщения своими адресами, чтобы доказать владение ими. Будьте осторожны, не подписывайте что-то неопределённое, так как фишинговые атаки могут обманным путём заставить вас подписать нежелательные сообщения. Подписывайте только те сообщения, с которыми вы согласны вплоть до мелочей. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Автоматически открыть порт для CasinoCoin-клиента на роутере. Работает только если Ваш роутер поддерживает UPnP, и данная функция включена. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Адрес, которым вы хотите подписать сообщение (напр. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Выбрать адрес из адресной книги - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Вставить адрес из буфера обмена - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Введите сообщение для подписи - - - - Copy the current signature to the system clipboard - Скопировать текущую подпись в системный буфер обмена - - - - &Copy Signature - &Копировать подпись - - - - Reset all sign message fields - Сбросить значения всех полей подписывания сообщений - - - - Clear &All - Очистить &всё - - - - Click "Sign Message" to get signature - Для создания подписи нажмите на "Подписать сообщение" - - - - Sign a message to prove you own this address - Подпишите сообщение для доказательства - - - - &Sign Message - &Подписать сообщение - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Введите адрес Bitcoin (напр. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Ошибка создания подписи - - - - %1 is not a valid address. - %1 не является правильным адресом. - - - - %1 does not refer to a key. - %1 не связан с ключом - - - - Private key for %1 is not available. - Секретный ключ для %1 не доступен - - - - Sign failed - Подписание не удалось. - - - - NetworkOptionsPage - - - Network - Сеть - - - + Map port using &UPnP Пробросить порт через &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Автоматически открыть порт для Bitcoin-клиента на роутере. Работает только если Ваш роутер поддерживает UPnP, и данная функция включена. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Подключаться к сети CasinoCoin через прокси SOCKS (например, при подключении через Tor). - - &Connect through SOCKS4 proxy: - &Подключаться через SOCKS4 прокси: + + &Connect through SOCKS proxy: + &Подключаться через SOCKS прокси: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Подключаться к сети Bitcoin через прокси SOCKS4 (например, при использовании Tor) - - - + Proxy &IP: &IP Прокси: - - &Port: - По&рт: - - - + IP address of the proxy (e.g. 127.0.0.1) IP-адрес прокси (например 127.0.0.1) - - Port of the proxy (e.g. 1234) - Порт прокси-сервера (например 1234) + + &Port: + По&рт: - - - OptionsDialog - - Options - Опции + + Port of the proxy (e.g. 9050) + Порт прокси-сервера (например, 9050) + + + + SOCKS &Version: + &Версия SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Версия SOCKS-прокси (например, 5) + + + + &Window + &Окно + + + + Show only a tray icon after minimizing the window. + Показывать только иконку в системном лотке после сворачивания окна. + + + + &Minimize to the tray instead of the taskbar + &Cворачивать в системный лоток вместо панели задач + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Сворачивать вместо закрытия. Если данная опция будет выбрана — приложение закроется только после выбора соответствующего пункта в меню. + + + + M&inimize on close + С&ворачивать при закрытии + + + + &Display + О&тображение + + + + User Interface &language: + &Язык интерфейса: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Здесь можно выбрать язык интерфейса. Настройки вступят в силу после перезапуска CasinoCoin. + + + + &Unit to show amounts in: + &Отображать суммы в единицах: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Выберите единицу измерения монет при отображении и отправке. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Показывать ли адреса CasinoCoin в списке транзакций. + + + + &Display addresses in transaction list + &Показывать адреса в списке транзакций + + + + &OK + О&К + + + + &Cancel + &Отмена + + + + &Apply + &Применить + + + + default + по умолчанию + + + + Confirm options reset + Подтвердите сброс опций + + + + Some settings may require a client restart to take effect. + Некоторые настройки могут потребовать перезапуск клиента, чтобы вступить в силу. + + + + Do you want to proceed? + Желаете продолжить? + + + + + Warning + Внимание + + + + + This setting will take effect after restarting CasinoCoin. + Эта настройка вступит в силу после перезапуска CasinoCoin + + + + The supplied proxy address is invalid. + Адрес прокси неверен. OverviewPage - + Form Форма - - - 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. - Отображаемая информация может быть устаревшей. Ваш бумажник автоматически синхронизируется с сетью Bitcoin после подключения, но этот процесс пока не завершён. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Отображаемая информация может быть устаревшей. Ваш бумажник автоматически синхронизируется с сетью CasinoCoin после подключения, но этот процесс пока не завершён. - + Balance: Баланс: - - Number of transactions: - Количество транзакций: - - - + Unconfirmed: Не подтверждено: - + Wallet Бумажник - + + Immature: + Незрелые: + + + + Mined balance that has not yet matured + Баланс добытых монет, который ещё не созрел + + + <b>Recent transactions</b> <b>Последние транзакции</b> - + Your current balance Ваш текущий баланс - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Общая сумма всех транзакций, которые до сих пор не подтверждены, и до сих пор не учитываются в текущем балансе - - Total number of transactions in wallet - Общее количество транзакций в Вашем бумажнике - - - - + + out of sync не синхронизировано + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Не удаётся запустить casinocoin: обработчик click-to-pay + + QRCodeDialog - + QR Code Dialog Диалог QR-кода - - QR Code - QR код - - - + Request Payment Запросить платёж - + Amount: Количество: - - BTC - BTC - - - + Label: Метка: - + Message: Сообщение: - + &Save As... &Сохранить как... - + Error encoding URI into QR Code. Ошибка кодирования URI в QR-код - + + The entered amount is invalid, please check. + Введено неверное количество, проверьте ещё раз. + + + Resulting URI too long, try to reduce the text for label / message. Получившийся URI слишком длинный, попробуйте сократить текст метки / сообщения. - + Save QR Code Сохранить QR-код - + PNG Images (*.png) PNG Изображения (*.png) @@ -1121,125 +1134,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - Окно отладки Bitcoin - - - + Client name Имя клиента - - - - - - - - - + + + + + + + + + + N/A Н/Д - + Client version Версия клиента - + &Information &Информация - - Client - Клиент + + Using OpenSSL version + Используется версия OpenSSL - + Startup time Время запуска - + Network Сеть - + Number of connections Число подключений - + On testnet В тестовой сети - + Block chain Цепь блоков - + Current number of blocks Текущее число блоков - + Estimated total blocks Расчётное число блоков - + Last block time Время последнего блока - - Debug logfile - Отладочный лог-файл - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - Открыть отладочный лог-файл Bitcoin из текущего каталога данных. Это может занять несколько секунд для больших лог-файлов. - - - + &Open &Открыть - + + Command-line options + Параметры командной строки + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Показать помощь по CasinoCoin-Qt, чтобы получить список доступных параметров командной строки. + + + + &Show + &Показать + + + &Console Консоль - + Build date Дата сборки - + + CasinoCoin - Debug window + CasinoCoin - Окно отладки + + + + CasinoCoin Core + Ядро CasinoCoin + + + + Debug log file + Отладочный лог-файл + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Открыть отладочный лог-файл CasinoCoin из текущего каталога данных. Это может занять несколько секунд для больших лог-файлов. + + + Clear console Очистить консоль - - Welcome to the Bitcoin RPC console. - Добро пожаловать в RPC-консоль Bitcoin. + + Welcome to the CasinoCoin RPC console. + Добро пожаловать в RPC-консоль CasinoCoin. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Используйте стрелки вверх и вниз для просмотра истории и <b>Ctrl-L</b> для очистки экрана. - + Type <b>help</b> for an overview of available commands. Напишите <b>help</b> для просмотра доступных команд. @@ -1247,109 +1281,109 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Отправка - + Send to multiple recipients at once Отправить нескольким получателям одновременно - - &Add Recipient + + Add &Recipient &Добавить получателя - + Remove all transaction fields Удалить все поля транзакции - + Clear &All Очистить &всё - + Balance: Баланс: - + 123.456 BTC 123.456 BTC - + Confirm the send action Подтвердить отправку - - &Send + + S&end &Отправить - + <b>%1</b> to %2 (%3) <b>%1</b> адресату %2 (%3) - + Confirm send coins Подтвердите отправку монет - + Are you sure you want to send %1? Вы уверены, что хотите отправить %1? - + and и - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Адрес получателя неверный, пожалуйста, перепроверьте. - + The amount to pay must be larger than 0. Количество монет для отправки должно быть больше 0. - + The amount exceeds your balance. Количество отправляемых монет превышает Ваш баланс - + The total exceeds your balance when the %1 transaction fee is included. Сумма превысит Ваш баланс, если комиссия в размере %1 будет добавлена к транзакции - + Duplicate address found, can only send to each address once per send operation. Обнаружен дублирующийся адрес. Отправка на один и тот же адрес возможна только один раз за одну операцию отправки - - Error: Transaction creation failed. - Ошибка: не удалось создать транзакцию. + + Error: Transaction creation failed! + Ошибка: не удалось создать транзакцию! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. Ошибка: В транзакции отказано. Такое может произойти, если некоторые монеты уже были потрачены, например, если Вы используете одну копию файла wallet.dat, а монеты были потрачены из другой копии, но не были отмечены как потраченные в этой. @@ -1357,217 +1391,456 @@ Address: %4 SendCoinsEntry - + Form Форма - + A&mount: Ко&личество: - + Pay &To: Полу&чатель: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Адрес, на который будет выслан платёж (например Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Введите метку для данного адреса (для добавления в адресную книгу) - + &Label: &Метка: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Адрес получателя платежа (например 1LA5FtQhnnWnkK6zjFfutR7Stiit4wKd63) - - - + Choose address from address book Выберите адрес из адресной книги - + Alt+A Alt+A - + Paste address from clipboard Вставить адрес из буфера обмена - + Alt+P Alt+P - + Remove this recipient Удалить этого получателя - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Введите Bitcoin-адрес (например 1LA5FtQhnnWnkK6zjFfutR7Stiit4wKd63) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Введите CasinoCoin-адрес (например 1LA5FtQhnnWnkK6zjFfutR7Stiit4wKd63) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Подписи - подписать/проверить сообщение + + + + &Sign Message + &Подписать сообщение + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Вы можете подписывать сообщения своими адресами, чтобы доказать владение ими. Будьте осторожны, не подписывайте что-то неопределённое, так как фишинговые атаки могут обманным путём заставить вас подписать нежелательные сообщения. Подписывайте только те сообщения, с которыми вы согласны вплоть до мелочей. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Адрес, которым вы хотите подписать сообщение (напр. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Выберите адрес из адресной книги + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Вставить адрес из буфера обмена + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Введите сообщение для подписи + + + + Signature + Подпись + + + + Copy the current signature to the system clipboard + Скопировать текущую подпись в системный буфер обмена + + + + Sign the message to prove you own this CasinoCoin address + Подписать сообщение, чтобы доказать владение адресом CasinoCoin + + + + Sign &Message + Подписать &Сообщение + + + + Reset all sign message fields + Сбросить значения всех полей подписывания сообщений + + + + + Clear &All + Очистить &всё + + + + &Verify Message + &Проверить сообщение + + + + Enter the signing 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. + Введите ниже адрес для подписи, сообщение (убедитесь, что переводы строк, пробелы, табы и т.п. в точности скопированы) и подпись, чтобы проверить сообщение. Убедитесь, что не скопировали лишнего в подпись, по сравнению с самим подписываемым сообщением, чтобы не стать жертвой атаки "man-in-the-middle". + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Адрес, которым было подписано сообщение (напр. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Проверить сообщение, чтобы убедиться, что оно было подписано указанным адресом CasinoCoin + + + + Verify &Message + Проверить &Сообщение + + + + Reset all verify message fields + Сбросить все поля проверки сообщения + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Введите адрес CasinoCoin (напр. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Нажмите "Подписать сообщение" для создания подписи + + + + Enter CasinoCoin signature + Введите подпись CasinoCoin + + + + + The entered address is invalid. + Введённый адрес неверен + + + + + + + Please check the address and try again. + Пожалуйста, проверьте адрес и попробуйте ещё раз. + + + + + The entered address does not refer to a key. + Введённый адрес не связан с ключом + + + + Wallet unlock was cancelled. + Разблокировка бумажника была отменена. + + + + Private key for the entered address is not available. + Для введённого адреса недоступен закрытый ключ + + + + Message signing failed. + Не удалось подписать сообщение + + + + Message signed. + Сообщение подписано + + + + The signature could not be decoded. + Подпись не может быть раскодирована. + + + + + Please check the signature and try again. + Пожалуйста, проверьте подпись и попробуйте ещё раз. + + + + The signature did not match the message digest. + Подпись не соответствует отпечатку сообщения. + + + + Message verification failed. + Проверка сообщения не удалась. + + + + Message verified. + Сообщение проверено. + + + + SplashScreen + + + The CasinoCoin developers + Разработчики CasinoCoin + + + + [testnet] + [тестовая сеть] TransactionDesc - - Open for %1 blocks - Открыто до получения %1 блоков - - - + Open until %1 Открыто до %1 - - %1/offline? - %1/оффлайн? + + %1/offline + %1/отключен - + %1/unconfirmed %1/не подтверждено - + %1 confirmations %1 подтверждений - - <b>Status:</b> - <b>Статус:</b> + + Status + Статус + + + + , broadcast through %n node(s) + , разослано через %n узел, разослано через %n узла, разослано через %n узлов - - , has not been successfully broadcast yet - , ещё не было успешно разослано + + Date + Дата - - , broadcast through %1 node - , разослано через %1 узел + + Source + Источник - - , broadcast through %1 nodes - , разослано через %1 узлов + + Generated + Сгенерированно - - <b>Date:</b> - <b>Дата:</b> + + + From + От - - <b>Source:</b> Generated<br> - <b>Источник:</b> [сгенерированно]<br> + + + + To + Для - - - <b>From:</b> - <b>Отправитель:</b> + + + own address + свой адрес - - unknown - неизвестно + + label + метка - - - - <b>To:</b> - <b>Получатель:</b> + + + + + + Credit + Кредит + + + + matures in %n more block(s) + будет доступно через %n блокбудет доступно через %n блокабудет доступно через %n блоков - - (yours, label: - (Ваш, метка: + + not accepted + не принято - - (yours) - (ваш) + + + + + Debit + Дебет - - - - - <b>Credit:</b> - <b>Кредит:</b> + + Transaction fee + Комиссия - - (%1 matures in %2 more blocks) - (%1 станет доступно через %2 блоков) + + Net amount + Чистая сумма - - (not accepted) - (не принято) + + Message + Сообщение - - - - <b>Debit:</b> - <b>Дебет:</b> - - - - <b>Transaction fee:</b> - <b>Комиссия:</b> - - - - <b>Net amount:</b> - <b>Общая сумма:</b> - - - - Message: - Сообщение: - - - - Comment: + + Comment Комментарий: - - Transaction ID: - Идентификатор транзакции: + + Transaction ID + ID транзакции - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Сгенерированные монеты должны подождать 120 блоков прежде, чем они смогут быть отправлены. Когда Вы сгенерировали этот блок он был отправлен в сеть, чтобы он был добавлен к цепочке блоков. Если данная процедура не удастся, статус изменится на «не подтверждено» и монеты будут непередаваемыми. Такое может случайно происходить в случае, если другой узел сгенерирует блок на несколько секунд раньше. + + Generated coins must mature 120 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. + Сгенерированные монеты должны подождать 120 блоков, прежде чем они могут быть потрачены. Когда Вы сгенерировали этот блок, он был отправлен в сеть для добавления в цепочку блоков. Если данная процедура не удастся, статус изменится на «не подтверждено», и монеты будут недействительны. Это иногда происходит в случае, если другой узел сгенерирует блок на несколько секунд раньше вас. + + + + Debug information + Отладочная информация + + + + Transaction + Транзакция + + + + Inputs + Входы + + + + Amount + Количество + + + + true + истина + + + + false + ложь + + + + , has not been successfully broadcast yet + , ещё не было успешно разослано + + + + Open for %n more block(s) + Открыто для ещё %n блокаОткрыто для ещё %n блоковОткрыто для ещё %n блоков + + + + unknown + неизвестно TransactionDescDialog - + Transaction details Детали транзакции - + This pane shows a detailed description of the transaction Данный диалог показывает детализированную статистику по выбранной транзакции @@ -1575,117 +1848,117 @@ Address: %4 TransactionTableModel - + Date Дата - + Type Тип - + Address Адрес - + Amount Количество - - Open for %n block(s) - Открыто для %n блокаОткрыто для %n блоковОткрыто для %n блоков + + Open for %n more block(s) + Открыто для ещё %n блокаОткрыто для ещё %n блоковОткрыто для ещё %n блоков - + Open until %1 Открыто до %1 - + Offline (%1 confirmations) Оффлайн (%1 подтверждений) - + Unconfirmed (%1 of %2 confirmations) Не подтверждено (%1 из %2 подтверждений) - + Confirmed (%1 confirmations) Подтверждено (%1 подтверждений) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) Добытыми монетами можно будет воспользоваться через %n блокДобытыми монетами можно будет воспользоваться через %n блокаДобытыми монетами можно будет воспользоваться через %n блоков - + This block was not received by any other nodes and will probably not be accepted! Этот блок не был получен другими узлами и, возможно, не будет принят! - + Generated but not accepted Сгенерированно, но не подтверждено - + Received with Получено - + Received from Получено от - + Sent to Отправлено - + Payment to yourself Отправлено себе - + Mined Добыто - + (n/a) [не доступно] - + Transaction status. Hover over this field to show number of confirmations. Статус транзакции. Подведите курсор к нужному полю для того, чтобы увидеть количество подтверждений. - + Date and time that the transaction was received. Дата и время, когда транзакция была получена. - + Type of transaction. Тип транзакции. - + Destination address of transaction. Адрес назначения транзакции. - + Amount removed from or added to balance. Сумма, добавленная, или снятая с баланса. @@ -1693,829 +1966,975 @@ Address: %4 TransactionView - - + + All Все - + Today Сегодня - + This week На этой неделе - + This month В этом месяце - + Last month За последний месяц - + This year В этом году - + Range... Промежуток... - + Received with Получено на - + Sent to Отправлено на - + To yourself Отправленные себе - + Mined Добытые - + Other Другое - + Enter address or label to search Введите адрес или метку для поиска - + Min amount Мин. сумма - + Copy address Копировать адрес - + Copy label Копировать метку - + Copy amount Скопировать сумму - + + Copy transaction ID + Скопировать ID транзакции + + + Edit label Изменить метку - + Show transaction details Показать подробности транзакции - + Export Transaction Data Экспортировать данные транзакций - + Comma separated file (*.csv) Текст, разделённый запятыми (*.csv) - + Confirmed Подтверждено - + Date Дата - + Type Тип - + Label Метка - + Address Адрес - + Amount Количество - + ID ID - + Error exporting Ошибка экспорта - + Could not write to file %1. Невозможно записать в файл %1. - + Range: Промежуток от: - + to до - - VerifyMessageDialog - - - Verify Signed Message - Проверить подписанное сообщение - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - Введите ниже сообщение и подпись (копируйте в точности переводы строк, пробелы, табы и иные невидимые или малозаметные символы), чтобы получить адрес Bitcoin, который использовался при подписывании сообщения. - - - - Verify a message and obtain the Bitcoin address used to sign the message - Проверить сообщение и получить адрес Bitcoin, который использовался для подписи - - - - &Verify Message - &Проверить сообщение - - - - Copy the currently selected address to the system clipboard - Скопировать выбранный адрес в системный буфер обмена - - - - &Copy Address - &Копировать адрес - - - - Reset all verify message fields - Сбросить все поля проверки сообщения - - - - Clear &All - Очистить &всё - - - - Enter Bitcoin signature - Введите подпись Bitcoin - - - - Click "Verify Message" to obtain address - Щёлкните "Проверить сообщение" для получения адреса - - - - - Invalid Signature - Неверная подпись - - - - The signature could not be decoded. Please check the signature and try again. - Не удаётся декодировать подпись. Проверьте подпись и попробуйте ещё раз. - - - - The signature did not match the message digest. Please check the signature and try again. - Подпись не совпадает с контрольной суммой сообщения. Проверьте подпись и попробуйте ещё раз. - - - - Address not found in address book. - Адрес не найден в адресной книге. - - - - Address found in address book: %1 - Адрес найден в адресной книге: %1 - - WalletModel - - Sending... - Отправка.... + + Send Coins + Отправка - WindowOptionsPage + WalletView - - Window - Окно + + &Export + &Экспорт - - &Minimize to the tray instead of the taskbar - &Cворачивать в системный лоток вместо панели задач + + Export the data in the current tab to a file + Экспортировать данные из вкладки в файл - - Show only a tray icon after minimizing the window - Показывать только иконку в системном лотке после сворачивания окна + + Backup Wallet + Сделать резервную копию бумажника - - M&inimize on close - С&ворачивать при закрытии + + Wallet Data (*.dat) + Данные бумажника (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Сворачивать вместо выхода, когда окно приложения закрывается. Если данная опция будет выбрана, приложение закроется только после выбора пункта Выход в меню. + + Backup Failed + Резервное копирование не удалось + + + + There was an error trying to save the wallet data to the new location. + При попытке сохранения данных бумажника в новое место произошла ошибка. + + + + Backup Successful + Резервное копирование успешно завершено + + + + The wallet data was successfully saved to the new location. + Данные бумажника успешно сохранены в новое место. bitcoin-core - - Bitcoin version + + CasinoCoin version Версия - + Usage: Использование: - - Send command to -server or bitcoind - Отправить команду на -server или bitcoind + + Send command to -server or casinocoind + Отправить команду на -server или casinocoind - + List commands Список команд - + Get help for a command Получить помощь по команде - + Options: Опции: - - Specify configuration file (default: bitcoin.conf) - Указать конфигурационный файл (по умолчанию: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Указать конфигурационный файл (по умолчанию: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Указать pid-файл (по умолчанию: bitcoin.pid) + + Specify pid file (default: casinocoind.pid) + Задать pid-файл (по умолчанию: casinocoin.pid) - - Generate coins - Генерировать монеты - - - - Don't generate coins - Не генерировать монеты - - - + Specify data directory - Укажите каталог данных + Задать каталог данных - + Set database cache size in megabytes (default: 25) Установить размер кэша базы данных в мегабайтах (по умолчанию: 25) - - Set database disk log size in megabytes (default: 100) - Установить размер лога базы данных в мегабайтах (по умолчанию: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Принимать входящие подключения на <port> (по умолчанию: 47950 или 17950 в тестовой сети) - - Specify connection timeout (in milliseconds) - Укажите таймаут соединения (в миллисекундах) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Принимать входящие подключения на <port> (по умолчанию: 8333 или 18333 в тестовой сети) - - - + Maintain at most <n> connections to peers (default: 125) Поддерживать не более <n> подключений к узлам (по умолчанию: 125) - - Connect only to the specified node - Подключаться только к указанному узлу - - - + Connect to a node to retrieve peer addresses, and disconnect Подключиться к узлу, чтобы получить список адресов других участников и отключиться - + Specify your own public address Укажите ваш собственный публичный адрес - - Only connect to nodes in network <net> (IPv4 or IPv6) - Подключаться только к узлам из сети <net> (IPv4 или IPv6) - - - - Try to discover public IP address (default: 1) - Попробовать обнаружить внешний IP-адрес (по умолчанию: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - Привязаться (bind) к указанному адресу. Используйте запись вида [хост]:порт для IPv6 - - - + Threshold for disconnecting misbehaving peers (default: 100) Порог для отключения неправильно ведущих себя узлов (по умолчанию: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Число секунд блокирования неправильно ведущих себя узлов (по умолчанию: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Максимальный размер буфера приёма на соединение, <n>*1000 байт (по умолчанию: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Произошла ошибка при открытии RPC-порта %u для прослушивания на IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Максимальный размер буфера отправки на соединение, <n>*1000 байт (по умолчанию: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Прослушивать подключения JSON-RPC на <порту> (по умолчанию: 47970 или для testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - Отключить базы данных блоков и адресов. Увеличивает время завершения работы (по умолчанию: 0) - - - + Accept command line and JSON-RPC commands Принимать командную строку и команды JSON-RPC - + Run in the background as a daemon and accept commands Запускаться в фоне как демон и принимать команды - + Use the test network Использовать тестовую сеть - - Output extra debugging information - Выводить дополнительную отладочную информацию + + Accept connections from outside (default: 1 if no -proxy or -connect) + Принимать подключения извне (по умолчанию: 1, если не используется -proxy или -connect) - - Prepend debug output with timestamp - Дописывать отметки времени к отладочному выводу - - - - Send trace/debug info to console instead of debug.log file - Выводить информацию трассировки/отладки на консоль вместо файла debug.log - - - - Send trace/debug info to debugger - Отправлять информацию трассировки/отладки в отладчик - - - - Username for JSON-RPC connections - Имя для подключений JSON-RPC - - - - Password for JSON-RPC connections - Пароль для подключений JSON-RPC - - - - Listen for JSON-RPC connections on <port> (default: 8332) - Ожидать подключения JSON-RPC на <порт> (по умолчанию: 8332) - - - - Allow JSON-RPC connections from specified IP address - Разрешить подключения JSON-RPC с указанного IP - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Посылать команды узлу, запущенному на <ip> (по умолчанию: 127.0.0.1) - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - Выполнить команду, когда появляется новый блок (%s в команде заменяется на хэш блока) - - - - Upgrade wallet to latest format - Обновить бумажник до последнего формата - - - - Set key pool size to <n> (default: 100) - Установить размер запаса ключей в <n> (по умолчанию: 100) - - - - Rescan the block chain for missing wallet transactions - Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций - - - - How many blocks to check at startup (default: 2500, 0 = all) - Сколько блоков проверять при запуске (по умолчанию: 2500, 0 = все) - - - - How thorough the block verification is (0-6, default: 1) - Насколько тщательно проверять блоки (0-6, по умолчанию: 1) - - - - Imports blocks from external blk000?.dat file - Импортировать блоки из внешнего файла blk000?.dat - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Параметры SSL: (см. Bitcoin Wiki для инструкций по настройке SSL) - - - - Use OpenSSL (https) for JSON-RPC connections - Использовать OpenSSL (https) для подключений JSON-RPC - - - - Server certificate file (default: server.cert) - Файл серверного сертификата (по умолчанию: server.cert) - - - - Server private key (default: server.pem) - Приватный ключ сервера (по умолчанию: server.pem) - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Разрешённые алгоритмы (по умолчанию: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - ВНИМАНИЕ: мало места на диске - - - - This help message - Эта справка - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Невозможно установить блокировку на рабочую директорию %s. Возможно, бумажник уже запущен. - - - - Bitcoin - Биткоин - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - Невозможно привязаться к %s на этом компьютере (bind вернул ошибку %d, %s) - - - - Connect through socks proxy - Подключаться через socks прокси - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - Выберите версию socks прокси (4 или 5, по умолчанию 5) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - Не использовать прокси для подключения к сети <net> (IPv4 или IPv6) - - - - Allow DNS lookups for -addnode, -seednode and -connect - Разрешить поиск в DNS для -addnode, -seednode и -connect - - - - Pass DNS requests to (SOCKS5) proxy - Выполнять DNS-запросы через (SOCKS5) прокси - - - - Loading addresses... - Загрузка адресов... - - - - Error loading blkindex.dat - Ошибка чтения blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - Ошибка загрузки wallet.dat: Бумажник поврежден - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Ошибка загрузки wallet.dat: бумажник требует более новую версию Bitcoin - - - - Wallet needed to be rewritten: restart Bitcoin to complete - Необходимо перезаписать бумажник, перезапустите Bitcoin для завершения операции. - - - - Error loading wallet.dat - Ошибка при загрузке wallet.dat - - - - Invalid -proxy address: '%s' - Неверный адрес -proxy: '%s' - - - - Unknown network specified in -noproxy: '%s' - В параметре -noproxy указана неизвестная сеть: '%s' - - - - Unknown network specified in -onlynet: '%s' - В параметре -onlynet указана неизвестная сеть: '%s' - - - - Unknown -socks proxy version requested: %i - В параметре -socks запрошена неизвестная версия: %i - - - - Cannot resolve -bind address: '%s' - Не удаётся разрешить адрес в параметре -bind: '%s' - - - - Not listening on any port - Никакие порты не прослушиваются - - - - Cannot resolve -externalip address: '%s' - Не удаётся разрешить адрес в параметре -externalip: '%s' - - - - Invalid amount for -paytxfee=<amount>: '%s' - Неверное количество в параметре -paytxfee=<кол-во>: '%s' - - - - Error: could not start node - Ошибка: не удалось запустить узел - - - - Error: Wallet locked, unable to create transaction - Ошибка: бумажник заблокирован, невозможно создать транзакцию - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Ошибка: эта транзакция требует комиссию в размере как минимум %s из-за её объёма, сложности или использования недавно полученных средств - - - - Error: Transaction creation failed - Ошибка: Создание транзакции не удалось - - - - Sending... - Отправка... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Ошибка: В транзакции отказано. Такое может произойти, если некоторые монеты уже были потрачены, например, если Вы используете одну копию файла wallet.dat, а монеты были потрачены из другой копии, но не были отмечены как потраченные в этой. - - - - Invalid amount - Неверное количество - - - - Insufficient funds - Недостаточно монет - - - - Loading block index... - Загрузка индекса блоков... - - - - Add a node to connect to and attempt to keep the connection open - Добавить узел для подключения и пытаться поддерживать соединение открытым - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - Невозможно привязаться к %s на этом компьютере. Возможно, Bitcoin уже работает. - - - - Find peers using internet relay chat (default: 0) - Найти участников через IRC (по умолчанию: 0) - - - - Accept connections from outside (default: 1) - Принимать входящие подключения (по умолчанию: 1) - - - - Find peers using DNS lookup (default: 1) - Найти участников с помощью запросов DNS (по умолчанию: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Использовать универсальный Plug and Play для проброса порта (по умолчанию: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Использовать универсальный Plug and Play для проброса порта (по умолчанию: 0) - - - - Fee per KB to add to transactions you send - Комиссия на килобайт, добавляемая к вашим транзакциям - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - ВНИМАНИЕ: установлена очень большое значение -paytxfee. Это комиссия, которую вы заплатите при проведении транзакции. - - - - Loading wallet... - Загрузка бумажника... - - - - Cannot downgrade wallet - Не удаётся понизить версию бумажника - - - - Cannot initialize keypool - Не удаётся инициализировать массив ключей - - - - Cannot write default address - Не удаётся записать адрес по умолчанию - - - - Rescanning... - Сканирование... - - - - Done loading - Загрузка завершена - - - - To use the %s option - Чтобы использовать опцию %s - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com %s, вы должны установить опцию rpcpassword в конфигурационном файле: %s Рекомендуется использовать следующий случайный пароль: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (вам не нужно запоминать этот пароль) -Если файл не существует, создайте его и установите право доступа только для чтения только для владельца. +Имя и пароль ДОЛЖНЫ различаться. +Если файл не существует, создайте его и установите права доступа только для владельца, только для чтения. +Также рекомендуется включить alertnotify для оповещения о проблемах; +Например: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Произошла ошибка при открытии на прослушивание IPv6 RCP-порта %u, возвращаемся к IPv4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Привязаться к указанному адресу и всегда прослушивать только его. Используйте [хост]:порт для IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Не удаётся установить блокировку на каталог данных %s. Возможно, CasinoCoin уже работает. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Ошибка: транзакция была отклонена! Это могло произойти в случае, если некоторые монеты в вашем бумажнике уже были потрачены, например, если вы используете копию wallet.dat, и монеты были использованы в копии, но не отмечены как потраченные здесь. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Ошибка: эта транзакция требует комиссию как минимум %s из-за суммы, сложности или использования недавно полученных средств! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Выполнить команду, когда приходит сообщение о тревоге (%s в команде заменяется на сообщение) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Выполнить команду, когда меняется транзакция в бумажнике (%s в команде заменяется на TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Максимальный размер высокоприоритетных/низкокомиссионных транзакций в байтах (по умолчанию: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Это пре-релизная тестовая сборка - используйте на свой страх и риск - не используйте для добычи или торговых приложений + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Внимание: установлено очень большое значение -paytxfee. Это комиссия, которую вы заплатите при проведении транзакции. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Внимание: отображаемые транзакции могут быть некорректны! Вам или другим узлам, возможно, следует обновиться. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Внимание: убедитесь, что дата и время на Вашем компьютере выставлены верно. Если Ваши часы идут неправильно, CasinoCoin будет работать некорректно. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Внимание: ошибка чтения wallet.dat! Все ключи прочитаны верно, но данные транзакций или записи адресной книги могут отсутствовать или быть неправильными. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Внимание: wallet.dat повреждён, данные спасены! Оригинальный wallet.dat сохранён как wallet.{timestamp}.bak в %s; если ваш баланс или транзакции некорректны, вы должны восстановить файл из резервной копии. + + + + Attempt to recover private keys from a corrupt wallet.dat + Попытаться восстановить приватные ключи из повреждённого wallet.dat + + + + Block creation options: + Параметры создания блоков: + + + + Connect only to the specified node(s) + Подключаться только к указанному узлу(ам) + + + + Corrupted block database detected + БД блоков повреждена + + + + Discover own IP address (default: 1 when listening and no -externalip) + Определить свой IP (по умолчанию: 1 при прослушивании и если не используется -externalip) + + + + Do you want to rebuild the block database now? + Пересобрать БД блоков прямо сейчас? + + + + Error initializing block database + Ошибка инициализации БД блоков + + + + Error initializing wallet database environment %s! + Ошибка инициализации окружения БД бумажника %s! + + + + Error loading block database + Ошибка чтения базы данных блоков + + + + Error opening block database + Не удалось открыть БД блоков + + + + Error: Disk space is low! + Ошибка: мало места на диске! + + + + Error: Wallet locked, unable to create transaction! + Ошибка: бумажник заблокирован, невозможно создать транзакцию! + + + + Error: system error: + Ошибка: системная ошибка: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Не удалось начать прослушивание на порту. Используйте -listen=0 если вас это устраивает. + + + + Failed to read block info + Не удалось прочитать информацию блока + + + + Failed to read block + Не удалось прочитать блок + + + + Failed to sync block index + Не удалось синхронизировать индекс блоков + + + + Failed to write block index + Не удалось записать индекс блоков + + + + Failed to write block info + Не удалось записать информацию блока + + + + Failed to write block + Не удалось записать блок + + + + Failed to write file info + Не удалось записать информацию файла + + + + Failed to write to coin database + Не удалось записать БД монет + + + + Failed to write transaction index + Не удалось записать индекс транзакций + + + + Failed to write undo data + Не удалось записать данные для отмены + + + + Find peers using DNS lookup (default: 1 unless -connect) + Искать узлы с помощью DNS (по умолчанию: 1, если не указан -connect) + + + + Generate coins (default: 0) + Включить добычу монет (по умолчанию: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Сколько блоков проверять при запуске (по умолчанию: 288, 0 = все) + + + + How thorough the block verification is (0-4, default: 3) + Насколько тщательно проверять блок (0-4, по умолчанию: 3) + + + + Not enough file descriptors available. + Недостаточно файловых дескрипторов. + + + + Rebuild block chain index from current blk000??.dat files + Перестроить индекс цепи блоков из текущих файлов blk000??.dat + + + + Set the number of threads to service RPC calls (default: 4) + Задать число потоков выполнения(по умолчанию: 4) + + + + Verifying blocks... + Проверка блоков... + + + + Verifying wallet... + Проверка бумажника... + + + + Imports blocks from external blk000??.dat file + Импортировать блоки из внешнего файла blk000??.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Задать число потоков проверки скрипта (вплоть до 16, 0=авто, <0 = оставить столько ядер свободными, по умолчанию: 0) + + + + Information + Информация + + + + Invalid -tor address: '%s' + Неверный адрес -tor: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Неверное количество в параметре -minrelaytxfee=<кол-во>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Неверное количество в параметре -mintxfee=<кол-во>: '%s' + + + + Maintain a full transaction index (default: 0) + Держать полный индекс транзакций (по умолчанию: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Максимальный размер буфера приёма на соединение, <n>*1000 байт (по умолчанию: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Максимальный размер буфера отправки на соединение, <n>*1000 байт (по умолчанию: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Принимать цепь блоков, только если она соответствует встроенным контрольным точкам (по умолчанию: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Подключаться только к узлам из сети <net> (IPv4, IPv6 или Tor) + + + + Output extra debugging information. Implies all other -debug* options + Выводить больше отладочной информации. Включает все остальные опции -debug* + + + + Output extra network debugging information + Выводить дополнительную сетевую отладочную информацию + + + + Prepend debug output with timestamp + Дописывать отметки времени к отладочному выводу + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + +Параметры SSL: (см. CasinoCoin Wiki для инструкций по настройке SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Выбрать версию SOCKS-прокси (4-5, по умолчанию: 5) + + + + Send trace/debug info to console instead of debug.log file + Выводить информацию трассировки/отладки на консоль вместо файла debug.log + + + + Send trace/debug info to debugger + Отправлять информацию трассировки/отладки в отладчик + + + + Set maximum block size in bytes (default: 250000) + Максимальный размер блока в байтах (по умолчанию: 250000) + + + + Set minimum block size in bytes (default: 0) + Минимальный размер блока в байтах (по умолчанию: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Сжимать файл debug.log при запуске клиента (по умолчанию: 1, если нет -debug) + + + + Signing transaction failed + Не удалось подписать транзакцию + + + + Specify connection timeout in milliseconds (default: 5000) + Таймаут соединения в миллисекундах (по умолчанию: 5000) + + + + System error: + Системная ошибка: + + + + Transaction amount too small + Объём транзакции слишком мал + + + + Transaction amounts must be positive + Объём транзакции должен быть положителен + + + + Transaction too large + Транзакция слишком большая + + + + Use UPnP to map the listening port (default: 0) + Использовать UPnP для проброса порта (по умолчанию: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Использовать UPnP для проброса порта (по умолчанию: 1, если используется прослушивание) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Использовать прокси для скрытых сервисов (по умолчанию: тот же, что и в -proxy) + + + + Username for JSON-RPC connections + Имя для подключений JSON-RPC + + + + Warning + Внимание + + + + Warning: This version is obsolete, upgrade required! + Внимание: эта версия устарела, требуется обновление! + + + + You need to rebuild the databases using -reindex to change -txindex + Вам необходимо пересобрать базы данных с помощью -reindex, чтобы изменить -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat повреждён, спасение данных не удалось + + + + Password for JSON-RPC connections + Пароль для подключений JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Разрешить подключения JSON-RPC с указанного IP + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Посылать команды узлу, запущенному на <ip> (по умолчанию: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Выполнить команду, когда появляется новый блок (%s в команде заменяется на хэш блока) + + + + Upgrade wallet to latest format + Обновить бумажник до последнего формата + + + + Set key pool size to <n> (default: 100) + Установить размер запаса ключей в <n> (по умолчанию: 100) + + + + Rescan the block chain for missing wallet transactions + Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций + + + + Use OpenSSL (https) for JSON-RPC connections + Использовать OpenSSL (https) для подключений JSON-RPC + + + + Server certificate file (default: server.cert) + Файл серверного сертификата (по умолчанию: server.cert) + + + + Server private key (default: server.pem) + Приватный ключ сервера (по умолчанию: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Разрешённые алгоритмы (по умолчанию: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Эта справка + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Невозможно привязаться к %s на этом компьютере (bind вернул ошибку %d, %s) + + + + Connect through socks proxy + Подключаться через socks прокси + + + + Allow DNS lookups for -addnode, -seednode and -connect + Разрешить поиск в DNS для -addnode, -seednode и -connect + + + + Loading addresses... + Загрузка адресов... + + + + Error loading wallet.dat: Wallet corrupted + Ошибка загрузки wallet.dat: Бумажник поврежден + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Ошибка загрузки wallet.dat: бумажник требует более новую версию CasinoCoin + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Необходимо перезаписать бумажник, перезапустите CasinoCoin для завершения операции. + + + + Error loading wallet.dat + Ошибка при загрузке wallet.dat + + + + Invalid -proxy address: '%s' + Неверный адрес -proxy: '%s' + + + + Unknown network specified in -onlynet: '%s' + В параметре -onlynet указана неизвестная сеть: '%s' + + + + Unknown -socks proxy version requested: %i + В параметре -socks запрошена неизвестная версия: %i + + + + Cannot resolve -bind address: '%s' + Не удаётся разрешить адрес в параметре -bind: '%s' + + + + Cannot resolve -externalip address: '%s' + Не удаётся разрешить адрес в параметре -externalip: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Неверное количество в параметре -paytxfee=<кол-во>: '%s' + + + + Invalid amount + Неверное количество + + + + Insufficient funds + Недостаточно монет + + + + Loading block index... + Загрузка индекса блоков... + + + + Add a node to connect to and attempt to keep the connection open + Добавить узел для подключения и пытаться поддерживать соединение открытым + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Невозможно привязаться к %s на этом компьютере. Возможно, CasinoCoin уже работает. + + + + Fee per KB to add to transactions you send + Комиссия на килобайт, добавляемая к вашим транзакциям + + + + Loading wallet... + Загрузка бумажника... + + + + Cannot downgrade wallet + Не удаётся понизить версию бумажника + + + + Cannot write default address + Не удаётся записать адрес по умолчанию + + + + Rescanning... + Сканирование... + + + + Done loading + Загрузка завершена + + + + To use the %s option + Чтобы использовать опцию %s + + + Error Ошибка - - An error occured while setting up the RPC port %i for listening: %s - Произошла ошибка в процессе открытия RPC-порта %i для прослушивания: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. Вы должны установить rpcpassword=<password> в конфигурационном файле: %s -Если файл не существует, создайте его и установите право доступа только для чтения только для владельца. - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - ВНИМАНИЕ: Проверьте дату и время, установленные на Вашем компьютере. Если Ваши часы идут не правильно Bitcoin может наботать не корректно. +Если файл не существует, создайте его и установите права доступа только для владельца. \ No newline at end of file diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index bd56dd1..bbf11fd 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -3,116 +3,155 @@ AboutDialog - - About Bitcoin - O Bitcoin + + About CasinoCoin + O CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b> verzia + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> verzia - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + Copyright + + + + + The CasinoCoin developers + + AddressBookPage - + Address Book Adresár - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Toto sú Vaše Bitcoin adresy pre prijímanie platieb. Môžete dať každému odosielateľovi inú rôznu adresu a tak udržiavať prehľad o platbách. - - - + Double-click to edit address or label Dvojklikom editovať adresu alebo popis - + Create a new address Vytvoriť novú adresu - + Copy the currently selected address to the system clipboard Kopírovať práve zvolenú adresu do systémového klipbordu - + &New Address - + &Nová adresa - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Toto sú Vaše CasinoCoin adresy pre prijímanie platieb. Môžete dať každému odosielateľovi inú rôznu adresu a tak udržiavať prehľad o platbách. + + + &Copy Address - + &Kopírovať adresu - + Show &QR Code Zobraz &QR Kód - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address Podpísať správu a dokázať že vlastníte túto adresu - - &Sign Message - &Podpísať Správu + + Sign &Message + Podpísať &správu - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Zmazať práve zvolená adresu zo zoznamu. Len adresy pre odosielanie sa dajú zmazať. + + Delete the currently selected address from the list + - + + Export the data in the current tab to a file + Exportovať tento náhľad do súboru + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete &Zmazať - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Kopírovať &popis - + &Edit + &Upraviť + + + + Send &Coins - + Export Address Book Data Exportovať dáta z adresára - + Comma separated file (*.csv) Čiarkou oddelený súbor (*.csv) - + Error exporting Chyba exportu. - + Could not write to file %1. Nedalo sa zapisovať do súboru %1. @@ -120,17 +159,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Popis - + Address Adresa - + (no label) (bez popisu) @@ -138,432 +177,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase Zadajte heslo - + New passphrase Nové heslo - + Repeat new passphrase Zopakujte nové heslo - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Zadajte nové heslo k peňaženke.<br/>Prosím použite heslo s dĺžkou aspon <b>10 alebo viac náhodných znakov</b>, alebo <b>8 alebo viac slov</b>. - + Encrypt wallet Zašifrovať peňaženku - + This operation needs your wallet passphrase to unlock the wallet. Táto operácia potrebuje heslo k vašej peňaženke aby ju mohla dešifrovať. - + Unlock wallet Odomknúť peňaženku - + This operation needs your wallet passphrase to decrypt the wallet. Táto operácia potrebuje heslo k vašej peňaženke na dešifrovanie peňaženky. - + Decrypt wallet Dešifrovať peňaženku - + Change passphrase Zmena hesla - + Enter the old and new passphrase to the wallet. Zadajte staré a nové heslo k peňaženke. - + Confirm wallet encryption Potvrďte šifrovanie peňaženky - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - VAROVANIE: Ak zašifrujete peňaženku a stratíte heslo, <b>STRATÍTE VŠETKY VAŠE BITCOINY</b>!⏎ -Ste si istí, že si želáte zašifrovať peňaženku? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Varovanie: Ak zašifrujete peňaženku a stratíte heslo, <b>STRATÍTE VŠETKY VAŠE CASINOCOINY</b>!⏎ - - + + Are you sure you wish to encrypt your wallet? + Ste si istí, že si želáte zašifrovať peňaženku? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + Varovanie: Caps Lock je zapnutý + + + + Wallet encrypted Peňaženka zašifrovaná - - Bitcoin 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. - Bitcoin sa teraz ukončí pre dokončenie procesu šifrovania. Pamätaj že šifrovanie peňaženky Ťa nemôže úplne ochrániť pred kráďežou bitcoinov pomocou škodlivého software. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin sa teraz ukončí pre dokončenie procesu šifrovania. Pamätaj že šifrovanie peňaženky Ťa nemôže úplne ochrániť pred kráďežou casinocoinov pomocou škodlivého software. - - - Warning: The Caps Lock key is on. - Varovanie: Caps Lock je zapnutý - - - - - - + + + + Wallet encryption failed Šifrovanie peňaženky zlyhalo - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Šifrovanie peňaženky zlyhalo kôli internej chybe. Vaša peňaženka nebola zašifrovaná. - - + + The supplied passphrases do not match. Zadané heslá nesúhlasia. - + Wallet unlock failed Odomykanie peňaženky zlyhalo - - - + + + The passphrase entered for the wallet decryption was incorrect. Zadané heslo pre dešifrovanie peňaženky bolo nesprávne. - + Wallet decryption failed Zlyhalo šifrovanie peňaženky. - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Heslo k peňaženke bolo úspešne zmenené. BitcoinGUI - - Bitcoin Wallet - Bitcoin peňaženka - - - + Sign &message... - + Podpísať &správu... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Synchronizácia so sieťou... - + &Overview &Prehľad - + Show general overview of wallet Zobraziť celkový prehľad o peňaženke - + &Transactions &Transakcie - + Browse transaction history Prechádzať históriu transakcií - - &Address Book - &Adresár - - - + Edit the list of stored addresses and labels Editovať zoznam uložených adries a popisov - - &Receive coins - &Prijať bitcoins - - - + Show the list of addresses for receiving payments Zobraziť zoznam adries pre prijímanie platieb. - - &Send coins - &Poslať bitcoins - - - - Prove you control an address - Dokázať že kontrolujete adresu - - - + E&xit U&končiť - + Quit application Ukončiť program - - &About %1 - &O %1 + + Show information about CasinoCoin + Zobraziť informácie o CasinoCoin - - Show information about Bitcoin - Zobraziť informácie o Bitcoin - - - + About &Qt O &Qt - + Show information about Qt Zobrazit informácie o Qt - + &Options... &Možnosti... - + &Encrypt Wallet... - + &Zašifrovať Peňaženku... - + &Backup Wallet... - + &Backup peňaženku... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + &Zmena Hesla... - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... - &Export... - - - - Send coins to a Bitcoin address + + Reindexing blocks on disk... - - Modify configuration options for Bitcoin - + + Send coins to a CasinoCoin address + Poslať casinocoins na adresu - - Show or hide the Bitcoin window - + + Modify configuration options for CasinoCoin + Upraviť možnosti nastavenia pre casinocoin - - Export the data in the current tab to a file - Exportovať tento náhľad do súboru - - - - Encrypt or decrypt wallet - Zašifrovať alebo dešifrovať peňaženku - - - + Backup wallet to another location Zálohovať peňaženku na iné miesto - + Change the passphrase used for wallet encryption Zmeniť heslo použité na šifrovanie peňaženky - + &Debug window - + &Okno pre ladenie - + Open debugging and diagnostic console - + Otvor konzolu pre ladenie a diagnostiku - + &Verify message... - - Verify a message signature + + + CasinoCoin - + + Wallet + Peňaženka + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + &O CasinoCoin + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Súbor - + &Settings &Nastavenia - + &Help &Pomoc - + Tabs toolbar Lišta záložiek - - Actions toolbar - Lišta aktvivít - - - - + + [testnet] [testovacia sieť] - - - Bitcoin client + + CasinoCoin client + CasinoCoin klient + + + + %n active connection(s) to CasinoCoin network + %n aktívne spojenie v CasinoCoin sieti%n aktívne spojenia v CasinoCoin sieti%n aktívnych spojení v Bitconi sieti + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. - - %n active connection(s) to Bitcoin network - %n aktívne spojenie v Bitcoin sieti%n aktívne spojenia v Bitcoin sieti%n aktívnych spojení v Bitconi sieti + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + - - Downloaded %1 blocks of transaction history. - Stiahnutých %1 blokov transakčnej histórie - - - - %n second(s) ago - pred %n sekundoupred %n sekundamipred %n sekundami - - - - %n minute(s) ago - pred %n minútoupred %n minútamipred %n minútami - - - - %n hour(s) ago - pred hodinoupred %n hodinamipred %n hodinami - - - - %n day(s) ago - včerapred %n dňamipred %n dňami + + %1 behind + - + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Aktualizovaný - + Catching up... Sťahujem... - - Last received block was generated %1. - Posledný prijatý blok bol generovaný %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Veľkosť tejto transakcie prekračuje limit. Stále ju však môžete odoslať za poplatok %1 ktorý bude pripísaný uzlu spracúvajúcemu vašu transakciu. Chcete zaplatiť poplatok? - - - + Confirm transaction fee - + Potvrď poplatok za transakciu. - + Sent transaction Odoslané transakcie - + Incoming transaction Prijaté transakcie - + Date: %1 Amount: %2 Type: %3 @@ -575,664 +642,632 @@ Typ: %3 Adresa: %4 - + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Peňaženka je <b>zašifrovaná</b> a momentálne <b>odomknutá</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Peňaženka je <b>zašifrovaná</b> a momentálne <b>zamknutá</b> - - Backup Wallet - Zálohovať peňaženku - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - Nastala chyba pri pokuse uložiť peňaženku na nové miesto. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - Displej - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Zvoľ východziu podjednotku ktorá sa bude zobrazovať v programe a pri odosielaní mincí. - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address Upraviť adresu - + &Label &Popis - + The label associated with this address book entry Popis priradený k tomuto záznamu v adresári - + &Address &Adresa - + The address associated with this address book entry. This can only be modified for sending addresses. Adresa spojená s týmto záznamom v adresári. Možno upravovať len pre odosielajúce adresy. - + New receiving address Nová adresa pre prijímanie - + New sending address Nová adresa pre odoslanie - + Edit receiving address Upraviť prijímacie adresy - + Edit sending address Upraviť odosielaciu adresu - + The entered address "%1" is already in the address book. Vložená adresa "%1" sa už nachádza v adresári. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Vložená adresa "%1" nieje platnou adresou casinocoin. - + Could not unlock wallet. Nepodarilo sa odomknúť peňaženku. - + New key generation failed. Generovanie nového kľúča zlyhalo. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + verzia - + Usage: Použitie: - - options + + command-line options - + UI options - + UI možnosti - + Set language, for example "de_DE" (default: system locale) - + Start minimized Spustiť minimalizované - + Show splash screen on startup (default: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + Options + Možnosti + + + + &Main + &Hlavné + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Pay transaction &fee Zaplatiť transakčné &poplatky - - Main - Hlavné + + Automatically start CasinoCoin after logging in to the system. + Automaticky spustiť CasinoCoin po zapnutí počítača - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Voliteľný transakčný poplatok za kB ktorý pomôže rýchlemu spracovaniu transakcie. Väčšina transakcií má 1 kB. Poplatok 0.01 je odporúčaný. + + &Start CasinoCoin on system login + &Spustiť CasinoCoin pri spustení systému správy okien - - &Start Bitcoin on system login + + Reset all client options to default. - - Automatically start Bitcoin after logging in to the system + + &Reset Options - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message + + &Network - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Môžete podpísať správy svojou adresou a dokázať, že ju vlastníte. Buďte opatrní a podpíšte len prehlásenia s ktorými plne súhlasíte, nakoľko útoky typu "phishing" Vás môžu lákať k ich podpísaniu. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automaticky otvorit port pre CasinoCoin na routeri. Toto funguje len ak router podporuje UPnP a je táto podpora aktivovaná. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Vyberte adresu z adresára - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Vložte adresu z klipbordu - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Sem vložte správu ktorú chcete podpísať - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Kliknite "Podpísať Správu" na získanie podpisu - - - - Sign a message to prove you own this address - Podpíšte správu aby ste dokázali že vlastníte túto adresu - - - - &Sign Message - &Podpísať Správu - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Zadajte Bitcoin adresu (napr. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Chyba podpisovania - - - - %1 is not a valid address. - %1 nieje platná adresa. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Súkromný kľúč pre %1 nieje k dispozícii. - - - - Sign failed - Podpisovanie neúspešné - - - - NetworkOptionsPage - - - Network - - - - + Map port using &UPnP Mapovať port pomocou &UPnP - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Automaticky otvorit port pre Bitcoin na routeri. Toto funguje len ak router podporuje UPnP a je táto podpora aktivovaná. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Pripojiť do siete CasinoCoin cez SOCKS proxy (napr. keď sa pripájate cez Tor) - - &Connect through SOCKS4 proxy: - &Pripojiť cez SOCKS4 proxy: + + &Connect through SOCKS proxy: + &Pripojiť cez SOCKS proxy: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Pripojiť do siete Bitcoin cez SOCKS4 proxy (napr. keď sa pripájate cez Tor) - - - + Proxy &IP: - - &Port: - - - - + IP address of the proxy (e.g. 127.0.0.1) IP addresa proxy (napr. 127.0.0.1) - - Port of the proxy (e.g. 1234) - Port proxy (napr. 1234) + + &Port: + - - - OptionsDialog - - Options - Možnosti + + Port of the proxy (e.g. 9050) + Port proxy (napr. 9050) + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + Zobraziť len ikonu na lište po minimalizovaní okna. + + + + &Minimize to the tray instead of the taskbar + Zobraziť len ikonu na lište po minimalizovaní okna. + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimalizovat namiesto ukončenia aplikácie keď sa okno zavrie. Keď je zvolená táto možnosť, aplikácia sa zavrie len po zvolení Ukončiť v menu. + + + + M&inimize on close + M&inimalizovať pri zavretí + + + + &Display + &Displej + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + &Zobrazovať hodnoty v jednotkách: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + &Zobraziť adresy zo zoznamu transakcií + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + Varovanie + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + OverviewPage - + Form Forma - - - 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - + Balance: Zostatok: - - Number of transactions: - Počet transakcií: - - - + Unconfirmed: Nepotvrdené: - + Wallet + Peňaženka + + + + Immature: - + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> <b>Nedávne transakcie</b> - + Your current balance Váš súčasný zostatok - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Suma transakcií ktoré ešte neboli potvrdené a nezapočítavaju sa do celkového zostatku. - - Total number of transactions in wallet - Celkový počet transakcií v peňaženke - - - - + + out of sync + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + QRCodeDialog - + QR Code Dialog - - QR Code - QR kód - - - + Request Payment Vyžiadať platbu - + Amount: Suma: - - BTC - BTC - - - + Label: Popis: - + Message: Správa: - + &Save As... &Uložiť ako... - + Error encoding URI into QR Code. + Chyba v zakódovaní URI do QR kódu + + + + The entered amount is invalid, please check. - + Resulting URI too long, try to reduce the text for label / message. - + Výsledné URI príliš dlhé, skráť text pre názov / správu. - + Save QR Code - + Ukladanie QR kódu - + PNG Images (*.png) - + PNG obrázky (*.png) RPCConsole - - Bitcoin debug window - - - - + Client name - + Meno klienta - - - - - - - - - + + + + + + + + + + N/A - + nie je k dispozícii - + Client version - + Verzia klienta - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Sieť - + Number of connections - + Počet pripojení - + On testnet - + Na testovacej sieti - + Block chain - + Reťazec blokov - + Current number of blocks - + Aktuálny počet blokov - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1240,327 +1275,566 @@ Adresa: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Poslať Bitcoins + Poslať CasinoCoins - + Send to multiple recipients at once Poslať viacerým príjemcom naraz - - &Add Recipient - + + Add &Recipient + &Pridať príjemcu - + Remove all transaction fields Odobrať všetky políčka transakcie - + Clear &All - + Zmazať &všetko - + Balance: Zostatok: - + 123.456 BTC 123.456 BTC - + Confirm the send action Potvrďte odoslanie - - &Send + + S&end &Odoslať - + <b>%1</b> to %2 (%3) <b>%1</b> do %2 (%3) - + Confirm send coins - Potvrdiť odoslanie bitcoins + Potvrdiť odoslanie casinocoins - + Are you sure you want to send %1? Ste si istí, že chcete odoslať %1? - + and a - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Adresa príjemcu je neplatná, prosím, overte ju. - + The amount to pay must be larger than 0. Suma na úhradu musí byť väčšia ako 0. - + The amount exceeds your balance. - + Suma je vyššia ako Váš zostatok. - + The total exceeds your balance when the %1 transaction fee is included. - + Suma celkom prevyšuje Váš zostatok ak sú započítané %1 transakčné poplatky. - + Duplicate address found, can only send to each address once per send operation. + Duplikát adresy objavený, je možné poslať na každú adresu len raz v jednej odchádzajúcej transakcii. + + + + Error: Transaction creation failed! - - Error: Transaction creation failed. - - - - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Chyba: Transakcia bola odmietnutá. Toto sa môže stať ak niektoré z mincí vo vašej peňaženke boli už utratené, napríklad ak používaš kópiu wallet.dat a mince označené v druhej kópií neboli označené ako utratené v tejto. SendCoinsEntry - + Form Forma - + A&mount: Su&ma: - + Pay &To: Zapla&tiť: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Vložte popis pre túto adresu aby sa pridala do adresára - + &Label: &Popis: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adresa pre odoslanie platby je (napr. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Zvoľte adresu z adresára - + Alt+A Alt+A - + Paste address from clipboard Vložiť adresu z klipbordu - + Alt+P Alt+P - + Remove this recipient Odstrániť tohto príjemcu - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Zadajte Bitcoin adresu (napr. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Zadajte CasinoCoin adresu (napr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Podpísať Správu + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Môžete podpísať správy svojou adresou a dokázať, že ju vlastníte. Buďte opatrní a podpíšte len prehlásenia s ktorými plne súhlasíte, nakoľko útoky typu "phishing" Vás môžu lákať k ich podpísaniu. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Zadajte CasinoCoin adresu (napr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Zvoľte adresu z adresára + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Vložte adresu z klipbordu + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Sem vložte správu ktorú chcete podpísať + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + Podpíšte správu aby ste dokázali že vlastníte túto adresu + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + Zmazať &všetko + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Zadajte CasinoCoin adresu (napr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Zadajte CasinoCoin adresu (napr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Kliknite "Podpísať Správu" na získanie podpisu + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testovacia sieť] TransactionDesc - - Open for %1 blocks - Otvorené pre %1 blokov - - - + Open until %1 Otvorené do %1 - - %1/offline? + + %1/offline - + %1/unconfirmed %1/nepotvrdené - + %1 confirmations %1 potvrdení - - <b>Status:</b> - <b>Stav:</b> + + Status + Stav + + + + , broadcast through %n node(s) + - + + Date + Dátum + + + + Source + + + + + Generated + + + + + + From + od + + + + + + To + + + + + + own address + + + + + label + popis + + + + + + + + Credit + Kredit + + + + matures in %n more block(s) + + + + + not accepted + neprijaté + + + + + + + Debit + Debet + + + + Transaction fee + Transakčný poplatok + + + + Net amount + Suma netto + + + + Message + Správa + + + + Comment + Komentár + + + + Transaction ID + ID transakcie + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + Transakcie + + + + Inputs + + + + + Amount + Suma + + + + true + + + + + false + + + + , has not been successfully broadcast yet , ešte nebola úspešne odoslaná - - - , broadcast through %1 node - , odoslaná cez %1 nódu + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , odoslaná cez %1 nód - - - - <b>Date:</b> - <b>Dátum:</b> - - - - <b>Source:</b> Generated<br> - <b>Zdroj:</b> Generovaný<br> - - - - - <b>From:</b> - <b>od:</b> - - - + unknown neznámy - - - - - <b>To:</b> - <b>Komu:</b> - - - - (yours, label: - (vaše, popis: - - - - (yours) - (vaše) - - - - - - - <b>Credit:</b> - <b>Kredit:</b> - - - - (%1 matures in %2 more blocks) - (%1 dospeje o %2 blokov) - - - - (not accepted) - (neprijaté) - - - - - - <b>Debit:</b> - <b>Debet:</b> - - - - <b>Transaction fee:</b> - <b>Transakčný poplatok:</b> - - - - <b>Net amount:</b> - <b>Suma netto:</b> - - - - Message: - Správa: - - - - Comment: - Komentár: - - - - Transaction ID: - ID transakcie: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - - TransactionDescDialog - + Transaction details Detaily transakcie - + This pane shows a detailed description of the transaction Táto časť obrazovky zobrazuje detailný popis transakcie @@ -1568,117 +1842,117 @@ Adresa: %4 TransactionTableModel - + Date Dátum - + Type Typ - + Address Adresa - + Amount Hodnota - - Open for %n block(s) + + Open for %n more block(s) - + Open until %1 Otvorené do %1 - + Offline (%1 confirmations) - + Offline (%1 potvrdení) - + Unconfirmed (%1 of %2 confirmations) Nepotvrdené (%1 z %2 potvrdení) - + Confirmed (%1 confirmations) Potvrdené (%1 potvrdení) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) - + This block was not received by any other nodes and will probably not be accepted! Ten blok nebol prijatý žiadnou inou nódou a pravdepodobne nebude akceptovaný! - + Generated but not accepted Vypočítané ale neakceptované - + Received with Prijaté s - + Received from Prijaté od: - + Sent to Odoslané na - + Payment to yourself Platba sebe samému - + Mined Vyfárané - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. Status transakcie. Pohybujte myšou nad týmto poľom a zjaví sa počet potvrdení. - + Date and time that the transaction was received. Dátum a čas prijatia transakcie. - + Type of transaction. Typ transakcie. - + Destination address of transaction. Cieľová adresa transakcie. - + Amount removed from or added to balance. Suma pridaná alebo odobraná k zostatku. @@ -1686,818 +1960,963 @@ Adresa: %4 TransactionView - - + + All Všetko - + Today Dnes - + This week Tento týždeň - + This month Tento mesiac - + Last month Minulý mesiac - + This year Tento rok - + Range... Rozsah... - + Received with Prijaté s - + Sent to Odoslané na - + To yourself Samému sebe - + Mined Vyfárané - + Other Iné - + Enter address or label to search Vložte adresu alebo popis pre vyhľadávanie - + Min amount Min množstvo - + Copy address Kopírovať adresu - + Copy label Kopírovať popis - + Copy amount Kopírovať sumu - + + Copy transaction ID + + + + Edit label Editovať popis - + Show transaction details - + Export Transaction Data Exportovať transakčné dáta - + Comma separated file (*.csv) Čiarkou oddelovaný súbor (*.csv) - + Confirmed Potvrdené - + Date Dátum - + Type Typ - + Label Popis - + Address Adresa - + Amount Suma - + ID ID - + Error exporting Chyba exportu - + Could not write to file %1. Nedalo sa zapisovať do súboru %1. - + Range: Rozsah: - + to do - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Kopírovať práve zvolenú adresu do systémového klipbordu - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Odosielanie... + + Send Coins + Poslať CasinoCoins - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - Zobraziť len ikonu na lište po minimalizovaní okna. + + Export the data in the current tab to a file + Exportovať tento náhľad do súboru - - Show only a tray icon after minimizing the window - Zobraziť len ikonu na lište po minimalizovaní okna. - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimalizovat namiesto ukončenia aplikácie keď sa okno zavrie. Keď je zvolená táto možnosť, aplikácia sa zavrie len po zvolení Ukončiť v menu. + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + bitcoin-core - - Bitcoin version - Bitcoin verzia + + CasinoCoin version + CasinoCoin verzia - + Usage: Použitie: - - Send command to -server or bitcoind - Odoslať príkaz -server alebo bitcoind + + Send command to -server or casinocoind + Odoslať príkaz -server alebo casinocoind - + List commands Zoznam príkazov - + Get help for a command Dostať pomoc pre príkaz - + Options: Možnosti: - - Specify configuration file (default: bitcoin.conf) - Určiť súbor s nastaveniami (predvolené: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Určiť súbor s nastaveniami (predvolené: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Určiť súbor pid (predvolené: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Určiť súbor pid (predvolené: casinocoind.pid) - - Generate coins - Počítaj bitcoins - - - - Don't generate coins - Nepočítaj bitcoins - - - + Specify data directory Určiť priečinok s dátami - + Set database cache size in megabytes (default: 25) - + Veľkosť vyrovnávajúcej pamäte pre databázu v megabytoch (predvolené:25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Načúvať spojeniam na <port> (prednastavené: 47950 alebo testovacia sieť: 17950) - - Specify connection timeout (in milliseconds) - Určiť aut spojenia (v milisekundách) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Načúvať spojeniam na <port> (prednastavené: 8333 alebo testovacia sieť: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Udržiavať maximálne <n> spojení (predvolené: 125) - - Connect only to the specified node - Pripojiť sa len k určenej nóde - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Hranica pre odpojenie zle sa správajúcich peerov (predvolené: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Počet sekúnd kedy sa zabráni zle sa správajúcim peerom znovupripojenie (predvolené: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Počúvať JSON-RPC spojeniam na <port> (predvolené: 47970 or testnet: 17970) - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - - - - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands Prijímať príkazy z príkazového riadku a JSON-RPC - + Run in the background as a daemon and accept commands Bežať na pozadí ako démon a prijímať príkazy - + Use the test network Použiť testovaciu sieť - - Output extra debugging information - Produkovať extra ladiace informácie - - - - Prepend debug output with timestamp - Pridať na začiatok ladiaceho výstupu časový údaj - - - - Send trace/debug info to console instead of debug.log file - Odoslať trace/debug informácie na konzolu namiesto debug.info žurnálu - - - - Send trace/debug info to debugger - Odoslať trace/debug informácie do ladiaceho programu - - - - Username for JSON-RPC connections - Užívateľské meno pre JSON-RPC spojenia - - - - Password for JSON-RPC connections - Heslo pre JSON-rPC spojenia - - - - Listen for JSON-RPC connections on <port> (default: 8332) - Počúvať JSON-RPC spojeniam na <port> (predvolené: 8332) - - - - Allow JSON-RPC connections from specified IP address - Povoliť JSON-RPC spojenia z určenej IP adresy. - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Poslať príkaz nóde bežiacej na <ip> (predvolené: 127.0.0.1) - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - Nastaviť zásobu adries na <n> (predvolené: 100) - - - - Rescan the block chain for missing wallet transactions - Znovu skenovať reťaz blokov pre chýbajúce transakcie - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - SSL možnosť: (pozrite Bitcoin Wiki pre návod na nastavenie SSL) - - - - Use OpenSSL (https) for JSON-RPC connections - Použiť OpenSSL (https) pre JSON-RPC spojenia - - - - Server certificate file (default: server.cert) - Súbor s certifikátom servra (predvolené: server.cert) - - - - Server private key (default: server.pem) - Súkromný kľúč servra (predvolené: server.pem) - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Prijateľné šifry (predvolené: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - Warning: Disk space is low - - - - - This help message - Táto pomocná správa - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - Načítavanie adries... - - - - Error loading blkindex.dat - Chyba načítania blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - Chyba načítania wallet.dat: Peňaženka je poškodená - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Chyba načítania wallet.dat: Peňaženka vyžaduje novšiu verziu Bitcoin - - - - Wallet needed to be rewritten: restart Bitcoin to complete - Bolo potrebné prepísať peňaženku: dokončite reštartovaním Bitcoin - - - - Error loading wallet.dat - Chyba načítania wallet.dat - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Chyba: Zlyhalo vytvorenie transakcie - - - - Sending... - Odosielanie... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Chyba: Transakcia bola odmietnutá. Toto sa môže stať ak niektoré z mincí vo vašej peňaženke boli už utratené, napríklad ak používaš kópiu wallet.dat a mince označené v druhej kópií neboli označené ako utratené v tejto. - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - Načítavanie zoznamu blokov... - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - Načítavam peňaženku... - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - Dokončené načítavanie - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Varovanie: -paytxfee je nastavené veľmi vysoko. Toto sú transakčné poplatky ktoré zaplatíte ak odošlete transakciu. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + Pripojiť sa len k určenej nóde + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + Neplatná adresa tor: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + Produkovať extra ladiace informácie. Implies all other -debug* options + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + Pridať na začiatok ladiaceho výstupu časový údaj + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL možnosť: (pozrite CasinoCoin Wiki pre návod na nastavenie SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + Odoslať trace/debug informácie na konzolu namiesto debug.info žurnálu + + + + Send trace/debug info to debugger + Odoslať trace/debug informácie do ladiaceho programu + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Určiť aut spojenia v milisekundách (predvolené: 5000) + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Skúsiť použiť UPnP pre mapovanie počúvajúceho portu (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Skúsiť použiť UPnP pre mapovanie počúvajúceho portu (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + Užívateľské meno pre JSON-RPC spojenia + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Heslo pre JSON-rPC spojenia + + + + Allow JSON-RPC connections from specified IP address + Povoliť JSON-RPC spojenia z určenej IP adresy. + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Poslať príkaz nóde bežiacej na <ip> (predvolené: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Vykonaj príkaz, ak zmeny v najlepšom bloku (%s v príkaze nahradí blok hash) + + + + Upgrade wallet to latest format + Aktualizuj peňaženku na najnovší formát. + + + + Set key pool size to <n> (default: 100) + Nastaviť zásobu adries na <n> (predvolené: 100) + + + + Rescan the block chain for missing wallet transactions + Znovu skenovať reťaz blokov pre chýbajúce transakcie + + + + Use OpenSSL (https) for JSON-RPC connections + Použiť OpenSSL (https) pre JSON-RPC spojenia + + + + Server certificate file (default: server.cert) + Súbor s certifikátom servra (predvolené: server.cert) + + + + Server private key (default: server.pem) + Súkromný kľúč servra (predvolené: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Prijateľné šifry (predvolené: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Táto pomocná správa + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + Pripojenie cez socks proxy + + + + Allow DNS lookups for -addnode, -seednode and -connect + Povoliť vyhľadávanie DNS pre pridanie nódy a spojenie + + + + Loading addresses... + Načítavanie adries... + + + + Error loading wallet.dat: Wallet corrupted + Chyba načítania wallet.dat: Peňaženka je poškodená + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Chyba načítania wallet.dat: Peňaženka vyžaduje novšiu verziu CasinoCoin + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Bolo potrebné prepísať peňaženku: dokončite reštartovaním CasinoCoin + + + + Error loading wallet.dat + Chyba načítania wallet.dat + + + + Invalid -proxy address: '%s' + Neplatná adresa proxy: '%s' + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + Neplatná suma pre -paytxfee=<amount>: '%s' + + + + Invalid amount + Neplatná suma + + + + Insufficient funds + Nedostatok prostriedkov + + + + Loading block index... + Načítavanie zoznamu blokov... + + + + Add a node to connect to and attempt to keep the connection open + Pridať nód na pripojenie a pokus o udržanie pripojenia otvoreného + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + Poplatok za kB ktorý treba pridať k odoslanej transakcii + + + + Loading wallet... + Načítavam peňaženku... + + + + Cannot downgrade wallet + Nie je možné prejsť na nižšiu verziu peňaženky + + + + Cannot write default address + Nie je možné zapísať predvolenú adresu. + + + + Rescanning... + + + + + Done loading + Dokončené načítavanie + + + + To use the %s option + Použiť %s možnosť. + + + Error - + Chyba - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Varovanie: Skontroluj či je na počítači nastavený správny čas a dátum. Ak sú hodiny nastavené nesprávne, Bitcoin nebude správne pracovať + Musíš nastaviť rpcpassword=<heslo> v konfiguračnom súbore: +%s +Ak súbor neexistuje, vytvor ho s oprávnením pre čítanie len vlastníkom (owner-readable-only) \ No newline at end of file diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 89d8f77..cf7cb09 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -3,116 +3,155 @@ AboutDialog - - About Bitcoin - О Bitcoin-у + + About CasinoCoin + О CasinoCoin-у - - <b>Bitcoin</b> version - <b>Bitcoin</b> верзија + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> верзија - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + Copyright + + + + + The CasinoCoin developers + + AddressBookPage - + Address Book Адресар - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Ово су Ваше Bitcoin адресе за примање уплата. Можете да сваком пошиљаоцу дате другачију адресу да би пратили ко је вршио уплате. - - - + Double-click to edit address or label Кликните два пута да промените адресу и/или етикету - + Create a new address Прави нову адресу - + Copy the currently selected address to the system clipboard Копира изабрану адресу на системски клипборд - + &New Address - + &Нова адреса - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Ово су Ваше CasinoCoin адресе за примање уплата. Можете да сваком пошиљаоцу дате другачију адресу да би пратили ко је вршио уплате. + + + &Copy Address - + Show &QR Code + Prikaži &QR kod + + + + Sign a message to prove you own a CasinoCoin address - - Sign a message to prove you own this address + + Sign &Message - - &Sign Message + + Delete the currently selected address from the list - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Брише изабрану адресу. Могуће је брисати само адресе са којих се шаље. + + Export the data in the current tab to a file + - + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + &Delete &Избриши - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + &Edit - + + Send &Coins + + + + Export Address Book Data Извоз података из адресара - + Comma separated file (*.csv) Зарезом одвојене вредности (*.csv) - + Error exporting Грешка током извоза - + Could not write to file %1. Није могуће писати у фајл %1. @@ -120,17 +159,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Етикета - + Address Адреса - + (no label) (без етикете) @@ -138,972 +177,947 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Enter passphrase Унесите лозинку - + New passphrase Нова лозинка - + Repeat new passphrase Поновите нову лозинку - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Унесите нову лозинку за приступ новчанику.<br/>Молимо Вас да лозинка буде <b>10 или више насумице одабраних знакова</b>, или <b>осам или више речи</b>. - + Encrypt wallet Шифровање новчаника - + This operation needs your wallet passphrase to unlock the wallet. Ова акција захтева лозинку Вашег новчаника да би га откључала. - + Unlock wallet Откључавање новчаника - + This operation needs your wallet passphrase to decrypt the wallet. Ова акција захтева да унесете лозинку да би дешифловала новчаник. - + Decrypt wallet Дешифровање новчаника - + Change passphrase Промена лозинке - + Enter the old and new passphrase to the wallet. Унесите стару и нову лозинку за шифровање новчаника. - + Confirm wallet encryption Одобрите шифровање новчаника - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - УПОЗОРЕЊЕ: Ако се ваш новчаник шифрује а потом изгубите лозинкзу, ви ћете <b>ИЗГУБИТИ СВЕ BITCOIN-Е</b>! -Да ли сте сигурни да желите да се новчаник шифује? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Упозорење: Ако се ваш новчаник шифрује а потом изгубите лозинкзу, ви ћете <b>ИЗГУБИТИ СВЕ CASINOCOIN-Е</b>! - - + + Are you sure you wish to encrypt your wallet? + Да ли сте сигурни да желите да се новчаник шифује? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + Wallet encrypted Новчаник је шифрован - - Bitcoin 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. - + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + CasinoCoin će se sad zatvoriti da bi završio proces enkripcije. Zapamti da enkripcija tvog novčanika ne može u potpunosti da zaštiti tvoje casinocoine da ne budu ukradeni od malawarea koji bi inficirao tvoj kompjuter. - - - Warning: The Caps Lock key is on. - - - - - - - + + + + Wallet encryption failed Неуспело шифровање новчаника - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Настала је унутрашња грешка током шифровања новчаника. Ваш новчаник није шифрован. - - + + The supplied passphrases do not match. Лозинке које сте унели се не подударају. - + Wallet unlock failed Неуспело откључавање новчаника - - - + + + The passphrase entered for the wallet decryption was incorrect. Лозинка коју сте унели за откључавање новчаника је нетачна. - + Wallet decryption failed Неуспело дешифровање новчаника - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Лозинка за приступ новчанику је успешно промењена. BitcoinGUI - - Bitcoin Wallet - Bitcoin новчаник - - - + Sign &message... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Синхронизација са мрежом у току... - + &Overview &Општи преглед - + Show general overview of wallet Погледајте општи преглед новчаника - + &Transactions &Трансакције - + Browse transaction history Претражите историјат трансакција - - &Address Book - &Адресар - - - + Edit the list of stored addresses and labels Уредите запамћене адресе и њихове етикете - - &Receive coins - П&римање новца - - - + Show the list of addresses for receiving payments Прегледајте листу адреса на којима прихватате уплате - - &Send coins - &Слање новца - - - - Prove you control an address - - - - + E&xit - + I&zlaz - + Quit application Напустите програм - - &About %1 - + + Show information about CasinoCoin + Прегледајте информације о CasinoCoin-у - - Show information about Bitcoin - Прегледајте информације о Bitcoin-у - - - + About &Qt - + О &Qt-у - + Show information about Qt - + Прегледајте информације о Qt-у - + &Options... П&оставке... - + &Encrypt Wallet... - + &Шифровање новчаника... - + &Backup Wallet... - + &Backup новчаника - + &Change Passphrase... - - - - - ~%n block(s) remaining - + Промени &лозинку... - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... - - &Export... - &Извоз... - - - - Send coins to a Bitcoin address + + Reindexing blocks on disk... - - Modify configuration options for Bitcoin - + + Send coins to a CasinoCoin address + Пошаљите новац на casinocoin адресу - - Show or hide the Bitcoin window - + + Modify configuration options for CasinoCoin + Изаберите могућности casinocoin-а - - Export the data in the current tab to a file - - - - - Encrypt or decrypt wallet - Шифровање и дешифровање новчаника - - - + Backup wallet to another location - + Change the passphrase used for wallet encryption Мењање лозинке којом се шифрује новчаник - + &Debug window - + Open debugging and diagnostic console - + &Verify message... - - Verify a message signature + + + CasinoCoin - + + Wallet + новчаник + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + &О CasinoCoin-у + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + &File &Фајл - + &Settings &Подешавања - + &Help П&омоћ - + Tabs toolbar Трака са картицама - - Actions toolbar - Трака са алаткама - - - - + + [testnet] [testnet] - - - Bitcoin client + + CasinoCoin client - - %n active connection(s) to Bitcoin network - %n активна веза са Bitcoin мрежом%n активне везе са Bitcoin мрежом%n активних веза са Bitcoin мрежом + + %n active connection(s) to CasinoCoin network + %n активна веза са CasinoCoin мрежом%n активне везе са CasinoCoin мрежом%n активних веза са CasinoCoin мрежом - - Downloaded %1 blocks of transaction history. - Преузето је %1 блокова историјата трансакција. - - - - %n second(s) ago - пре %n секундпре %n секундепре %n секунди - - - - %n minute(s) ago - пре %n минутпре %n минутапре %n минута - - - - %n hour(s) ago - пре %n сатпре %n сатапре %n сати - - - - %n day(s) ago - пре %n данпре %n данапре %n дана + + No block source available... + - + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Ажурно - + Catching up... Ажурирање у току... - - Last received block was generated %1. - Последњи примљени блок је направљен %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Ова трансакција је превелика. И даље је можете послати уз накнаду од %1, која ће отићи чвору који прерађује трансакцију и помаже издржавању целе мреже. Да ли желите да дате напојницу? - - - + Confirm transaction fee - + Sent transaction Послана трансакција - + Incoming transaction Придошла трансакција - + Date: %1 Amount: %2 Type: %3 Address: %4 + Datum: %1⏎ Iznos: %2⏎ Tip: %3⏎ Adresa: %4⏎ + + + + + URI handling - + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Новчаник јс <b>шифрован</b> и тренутно <b>откључан</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Новчаник јс <b>шифрован</b> и тренутно <b>закључан</b> - - Backup Wallet - - - - - Wallet Data (*.dat) - - - - - Backup Failed - - - - - There was an error trying to save the wallet data to the new location. - - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - DisplayOptionsPage - - - Display - - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - - - EditAddressDialog - + Edit Address - + Измени адресу - + &Label - + &Етикета - + The label associated with this address book entry - + &Address - + &Адреса - + The address associated with this address book entry. This can only be modified for sending addresses. - + New receiving address - + New sending address - + Edit receiving address - + Edit sending address - + The entered address "%1" is already in the address book. + Унешена адреса "%1" се већ налази у адресару. + + + + The entered address "%1" is not a valid CasinoCoin address. - - The entered address "%1" is not a valid Bitcoin address. - - - - + Could not unlock wallet. Немогуће откључати новчаник. - + New key generation failed. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt + + + CasinoCoin-Qt - + version - + верзија - + Usage: + Korišćenje: + + + + command-line options - - options - - - - + UI options - + Set language, for example "de_DE" (default: system locale) - + Start minimized - + Show splash screen on startup (default: 1) - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - - - - - Main - - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - - - - - Alt+A - - - - - Paste address from clipboard - - - - - Alt+P - - - - - Enter the message you want to sign here - - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - - - - - Sign a message to prove you own this address - - - - - &Sign Message - - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - - Error signing - - - - - %1 is not a valid address. - - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - - - - - Sign failed - - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - - - - - &Connect through SOCKS4 proxy: - - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - - - - - Port of the proxy (e.g. 1234) - - - OptionsDialog - + Options + Поставке + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + &Јединица за приказивање износа: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. OverviewPage - + Form + Форма + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. - - - 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. - - - - + Balance: - - Number of transactions: - - - - + Unconfirmed: - + Непотврђено: - + Wallet + новчаник + + + + Immature: - + + Mined balance that has not yet matured + + + + <b>Recent transactions</b> - + <b>Недавне трансакције</b> - + Your current balance - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - - Total number of transactions in wallet - Укупан број трансакција у новчанику - - - - + + out of sync + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + QRCodeDialog - + QR Code Dialog - - QR Code - - - - + Request Payment - + Zatraži isplatu - + Amount: - + Iznos: - - BTC - - - - + Label: - + &Етикета - + Message: - + Poruka: - + &Save As... - + &Snimi kao... - + Error encoding URI into QR Code. - + + The entered amount is invalid, please check. + + + + Resulting URI too long, try to reduce the text for label / message. - + Save QR Code - + PNG Images (*.png) @@ -1111,125 +1125,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - - - - - - - - - + + + + + + + + + + N/A - + Client version - + &Information - - Client + + Using OpenSSL version - + Startup time - + Network - + Number of connections - + On testnet - + Block chain - + Current number of blocks - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + &Console - + Build date - + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Type <b>help</b> for an overview of available commands. @@ -1237,109 +1272,109 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - + Слање новца - + Send to multiple recipients at once - - &Add Recipient + + Add &Recipient - + Remove all transaction fields - + Ukloni sva polja sa transakcijama - + Clear &All - + Balance: - + 123.456 BTC - + Confirm the send action - + Потврди акцију слања - - &Send + + S&end &Пошаљи - + <b>%1</b> to %2 (%3) - + Confirm send coins - + Are you sure you want to send %1? Да ли сте сигурни да желите да пошаљете %1? - + and + и + + + + The recipient address is not valid, please recheck. - - The recepient address is not valid, please recheck. - - - - + The amount to pay must be larger than 0. - + The amount exceeds your balance. - + The total exceeds your balance when the %1 transaction fee is included. - + Duplicate address found, can only send to each address once per send operation. - - Error: Transaction creation failed. + + Error: Transaction creation failed! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -1347,1154 +1382,1538 @@ Address: %4 SendCoinsEntry - + Form - + Форма - + A&mount: - + Pay &To: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book - + &Label: - + &Етикета - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - + Choose address from address book - + Izaberite adresu iz adresara - + Alt+A - + Paste address from clipboard - + Alt+P - + Remove this recipient - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Unesite CasinoCoin adresu (n.pr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Unesite CasinoCoin adresu (n.pr. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [testnet] + TransactionDesc - - Open for %1 blocks - - - - + Open until %1 + Otvorite do %1 + + + + %1/offline - - %1/offline? - - - - + %1/unconfirmed - + %1/nepotvrdjeno - + %1 confirmations + %1 potvrde + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + datum + + + + Source - - <b>Status:</b> + + Generated - + + + From + + + + + + + To + + + + + + own address + + + + + label + етикета + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + iznos + + + + true + + + + + false + + + + , has not been successfully broadcast yet - + , nije još uvek uspešno emitovan + + + + Open for %n more block(s) + - - , broadcast through %1 node - - - - - , broadcast through %1 nodes - - - - - <b>Date:</b> - - - - - <b>Source:</b> Generated<br> - - - - - - <b>From:</b> - - - - + unknown - - - - - - - <b>To:</b> - - - - - (yours, label: - - - - - (yours) - - - - - - - - <b>Credit:</b> - - - - - (%1 matures in %2 more blocks) - - - - - (not accepted) - - - - - - - <b>Debit:</b> - - - - - <b>Transaction fee:</b> - - - - - <b>Net amount:</b> - - - - - Message: - - - - - Comment: - - - - - Transaction ID: - - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - + nepoznato TransactionDescDialog - + Transaction details - + detalji transakcije - + This pane shows a detailed description of the transaction - + Ovaj odeljak pokazuje detaljan opis transakcije TransactionTableModel - + Date - + datum - + Type - + tip - + Address Адреса - + Amount - + iznos - - Open for %n block(s) + + Open for %n more block(s) - + Open until %1 - + Otvoreno do %1 - + Offline (%1 confirmations) - + Offline * van mreže (%1 potvrdjenih) - + Unconfirmed (%1 of %2 confirmations) - + Nepotvrdjeno (%1 of %2 potvrdjenih) - + Confirmed (%1 confirmations) - + Potvrdjena (%1 potvrdjenih) - - Mined balance will be available in %n more blocks + + Mined balance will be available when it matures in %n more block(s) - + This block was not received by any other nodes and will probably not be accepted! - + Ovaj blok nije primljen od ostalih čvorova (nodova) i verovatno neće biti prihvaćen! - + Generated but not accepted - + Generisan ali nije prihvaćen - + Received with - + Primljen sa - + Received from - + Primljeno od - + Sent to - + Poslat ka - + Payment to yourself - + Isplata samom sebi - + Mined - + Minirano - + (n/a) - + (n/a) - + Transaction status. Hover over this field to show number of confirmations. - + Status vaše transakcije. Predjite mišem preko ovog polja da bi ste videli broj konfirmacija - + Date and time that the transaction was received. - + Datum i vreme primljene transakcije. - + Type of transaction. - + Tip transakcije - + Destination address of transaction. - + Destinacija i adresa transakcije - + Amount removed from or added to balance. - + Iznos odbijen ili dodat balansu. TransactionView - - + + All - + Sve - + Today - + Danas - + This week - + ove nedelje - + This month - + Ovog meseca - + Last month - + Prošlog meseca - + This year - + Ove godine - + Range... - + Opseg... - + Received with - + Primljen sa - + Sent to - + Poslat ka - + To yourself - + Vama - samom sebi - + Mined - + Minirano - + Other - + Drugi - + Enter address or label to search - + Navedite adresu ili naziv koji bi ste potražili - + Min amount - + Min iznos - + Copy address - + kopiraj adresu - + Copy label - + kopiraj naziv - + Copy amount + kopiraj iznos + + + + Copy transaction ID - + Edit label - + promeni naziv - + Show transaction details - + Export Transaction Data - + Izvezi podatke o transakcijama - + Comma separated file (*.csv) Зарезом одвојене вредности (*.csv) - + Confirmed - + Potvrdjen - + Date - + datum - + Type - + tip - + Label Етикета - + Address Адреса - + Amount - + iznos - + ID - + Error exporting Грешка током извоза - + Could not write to file %1. Није могуће писати у фајл %1. - + Range: - + Opseg: - + to - - - - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Копира изабрану адресу на системски клипборд - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - + do WalletModel - - Sending... - Слање у току... + + Send Coins + Слање новца - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar + + Export the data in the current tab to a file - - Show only a tray icon after minimizing the window + + Backup Wallet - - M&inimize on close + + Wallet Data (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. bitcoin-core - - Bitcoin version - + + CasinoCoin version + CasinoCoin верзија - + Usage: - + Korišćenje: - - Send command to -server or bitcoind - + + Send command to -server or casinocoind + Pošalji naredbu na -server ili casinocoinid + - + List commands - + Listaj komande - + Get help for a command - + Zatraži pomoć za komande - + Options: - + Opcije - - Specify configuration file (default: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Potvrdi željeni konfiguracioni fajl (podrazumevani:casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + Konkretizuj pid fajl (podrazumevani: casinocoind.pid) - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory - + Gde je konkretni data direktorijum - + Set database cache size in megabytes (default: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Slušaj konekcije na <port> (default: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - - - - + Maintain at most <n> connections to peers (default: 125) - + Održavaj najviše <n> konekcija po priključku (default: 125) + - - Connect only to the specified node - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - - - - + Accept command line and JSON-RPC commands - + Prihvati komandnu liniju i JSON-RPC komande - + Run in the background as a daemon and accept commands - + Radi u pozadini kao daemon servis i prihvati komande - + Use the test network - - - - - Output extra debugging information - - - - - Prepend debug output with timestamp - - - - - Send trace/debug info to console instead of debug.log file - - - - - Send trace/debug info to debugger - - - - - Username for JSON-RPC connections - - - - - Password for JSON-RPC connections - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - - - - - Allow JSON-RPC connections from specified IP address - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) - - - - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - - - - - Rescan the block chain for missing wallet transactions - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - - - - - Use OpenSSL (https) for JSON-RPC connections - - - - - Server certificate file (default: server.cert) - - - - - Server private key (default: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - - - Bitcoin - - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - - - - - Error loading blkindex.dat - - - - - Error loading wallet.dat: Wallet corrupted - - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - - - - - Wallet needed to be rewritten: restart Bitcoin to complete - - - - - Error loading wallet.dat - - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - - - - - Sending... - Слање у току... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - - - - - Invalid amount - - - - - Insufficient funds - - - - - Loading block index... - - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - Новчаник се учитава... - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - - - - - Done loading - + Koristi testnu mrežu - - To use the %s option + + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + Korisničko ime za JSON-RPC konekcije + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Lozinka za JSON-RPC konekcije + + + + Allow JSON-RPC connections from specified IP address + Dozvoli JSON-RPC konekcije sa posebne IP adrese + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Pošalji komande to nodu koji radi na <ip> (default: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + Odredi veličinu zaštićenih ključeva na <n> (default: 100) + + + + Rescan the block chain for missing wallet transactions + Ponovo skeniraj lanac blokova za nedostajuće transakcije iz novčanika + + + + Use OpenSSL (https) for JSON-RPC connections + Koristi OpenSSL (https) za JSON-RPC konekcije + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + privatni ključ za Server (podrazumevan: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Prihvatljive cifre (podrazumevano: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Ova poruka Pomoći + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + učitavam adrese.... + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + Učitavam blok indeksa... + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + Новчаник се учитава... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + Ponovo skeniram... + + + + Done loading + Završeno učitavanje + + + + To use the %s option + + + + Error - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index d41390f..e96b947 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -3,122 +3,161 @@ AboutDialog - - About Bitcoin - Om Bitcoin + + About CasinoCoin + Om CasinoCoin - - <b>Bitcoin</b> version - <b>Bitcoin</b>-version + + <b>CasinoCoin</b> version + <b>CasinoCoin</b>-version - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Copyright © 2009-2012 Bitcoin-utvecklarna - + Detta är experimentell mjukvara. -Distribuerad under mjukvarulicensen MIT/X11, se den medföljande filen license.txt eller http://www.opensource.org/licenses/mit-license.php. + +Distribuerad under mjukvarulicensen MIT/X11, se den medföljande filen COPYING eller http://www.opensource.org/licenses/mit-license.php. Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användning i OpenSSL Toolkit (http://www.openssl.org/) och kryptografisk mjukvara utvecklad av Eric Young (eay@cryptsoft.com) samt UPnP-mjukvara skriven av Thomas Bernard. + + + Copyright + Copyright + + + + The CasinoCoin developers + CasinoCoin-utvecklarna + AddressBookPage - + Address Book Adressbok - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Detta är dina Bitcoin-adresser för att ta emot betalningar. Du kan ge varje avsändare en egen adress så att du kan hålla reda på vem som betalar dig. - - - + Double-click to edit address or label Dubbel-klicka för att ändra adressen eller etiketten - + Create a new address Skapa ny adress - + Copy the currently selected address to the system clipboard Kopiera den markerade adressen till systemets Urklipp - + &New Address &Ny adress - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Detta är dina CasinoCoin-adresser för att ta emot betalningar. Du kan ge varje avsändare en egen adress så att du kan hålla reda på vem som betalar dig. + + + &Copy Address &Kopiera adress - + Show &QR Code Visa &QR-kod - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address Signera ett meddelande för att bevisa att du äger denna adress - - &Sign Message - &Signera meddelande + + Sign &Message + Signera &Meddelande - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Ta bort den valda adressen från listan. Bara avsändar-adresser kan tas bort. + + Delete the currently selected address from the list + Ta bort den valda adressen från listan - + + Export the data in the current tab to a file + Exportera informationen i den nuvarande fliken till en fil + + + + &Export + &Exportera + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Verifiera meddelandet för att vara säker på att den var signerad med den specificerade CasinoCoin-adressen + + + + &Verify Message + &Verifiera Meddelande + + + &Delete - &Ta bort + &Radera - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Detta är dina CasinoCoin adresser för att skicka betalningar. Kolla alltid summan och den mottagande adressen innan du skickar CasinoCoins. + + + Copy &Label Kopiera &etikett - + &Edit &Editera - + + Send &Coins + Skicka &CasinoCoins + + + Export Address Book Data Exportera Adressbok - + Comma separated file (*.csv) Kommaseparerad fil (*.csv) - + Error exporting Fel vid export - + Could not write to file %1. Kunde inte skriva till filen %1. @@ -126,17 +165,17 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni AddressTableModel - + Label Etikett - + Address Adress - + (no label) (Ingen etikett) @@ -144,432 +183,460 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni AskPassphraseDialog - + Passphrase Dialog Lösenords Dialog - + Enter passphrase Ange lösenord - + New passphrase Nytt lösenord - + Repeat new passphrase Upprepa nytt lösenord - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Ange plånbokens nya lösenord. <br/> Använd ett lösenord på <b>10 eller fler slumpmässiga tecken,</b> eller <b>åtta eller fler ord.</b> - + Encrypt wallet Kryptera plånbok - + This operation needs your wallet passphrase to unlock the wallet. Denna operation behöver din plånboks lösenord för att låsa upp plånboken. - + Unlock wallet Lås upp plånbok - + This operation needs your wallet passphrase to decrypt the wallet. Denna operation behöver din plånboks lösenord för att dekryptera plånboken. - + Decrypt wallet Dekryptera plånbok - + Change passphrase Ändra lösenord - + Enter the old and new passphrase to the wallet. Ange plånbokens gamla och nya lösenord. - + Confirm wallet encryption Bekräfta kryptering av plånbok - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - VARNING: Om du krypterar din plånbok och glömmer ditt lösenord, kommer du att <b>FÖRLORA ALLA DINA TILLGÅNGAR</b>! -Är du säker på att du vill kryptera din plånbok? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + VARNING: Om du krypterar din plånbok och glömmer ditt lösenord, kommer du att <b>FÖRLORA ALLA DINA TILLGÅNGAR</b>! - - + + Are you sure you wish to encrypt your wallet? + Är du säker på att du vill kryptera din plånbok? + + + + 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. + VIKTIGT: Alla tidigare säkerhetskopior du har gjort av plånbokens fil ska ersättas med den nya genererade, krypterade plånboks filen. Av säkerhetsskäl kommer tidigare säkerhetskopior av den okrypterade plånboks filen blir oanvändbara när du börjar använda en ny, krypterad plånbok. + + + + + Warning: The Caps Lock key is on! + Varning: Caps Lock är påslaget! + + + + Wallet encrypted Plånboken är krypterad - - Bitcoin 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. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. Programmet 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. - - - Warning: The Caps Lock key is on. - Varning: Caps Lock är påslaget - - - - - - + + + + Wallet encryption failed Kryptering av plånbok misslyckades - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Kryptering av plånbok misslyckades på grund av ett internt fel. Din plånbok blev inte krypterad. - - + + The supplied passphrases do not match. De angivna lösenorden överensstämmer inte. - + Wallet unlock failed Upplåsning av plånbok misslyckades - - - + + + The passphrase entered for the wallet decryption was incorrect. Lösenordet för dekryptering av plånbok var felaktig. - + Wallet decryption failed Dekryptering av plånbok misslyckades - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Plånbokens lösenord har ändrats. BitcoinGUI - - Bitcoin Wallet - Bitcoin-plånbok - - - + Sign &message... Signera &meddelande... - - Show/Hide &Bitcoin - Visa/Göm &Bitcoin - - - + Synchronizing with network... Synkroniserar med nätverk... - + &Overview &Översikt - + Show general overview of wallet Visa översiktsvy av plånbok - + &Transactions &Transaktioner - + Browse transaction history Bläddra i transaktionshistorik - - &Address Book - &Adressbok - - - + Edit the list of stored addresses and labels Redigera listan med lagrade adresser och etiketter - - &Receive coins - &Ta emot bitcoins - - - + Show the list of addresses for receiving payments Visa listan med adresser för att ta emot betalningar - - &Send coins - &Skicka bitcoins - - - - Prove you control an address - Bevisa att du kontrollerar en adress - - - + E&xit &Avsluta - + Quit application Avsluta programmet - - &About %1 - &Om %1 + + Show information about CasinoCoin + Visa information om CasinoCoin - - Show information about Bitcoin - Visa information om Bitcoin - - - + About &Qt Om &Qt - + Show information about Qt Visa information om Qt - + &Options... &Alternativ... - + &Encrypt Wallet... &Kryptera plånbok... - + &Backup Wallet... &Säkerhetskopiera plånbok... - + &Change Passphrase... &Byt Lösenord... - - - ~%n block(s) remaining - ~%n block återstår~%n block återstår + + + Importing blocks from disk... + Importerar block från disk... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Laddat ner %1 av %2 block från transaktionshistoriken (%3% klart). + + Reindexing blocks on disk... + Återindexerar block på disken... - - &Export... - &Exportera... + + Send coins to a CasinoCoin address + Skicka mynt till en CasinoCoin-adress - - Send coins to a Bitcoin address - Skicka mynt till en Bitcoin-adress + + Modify configuration options for CasinoCoin + Ändra konfigurationsalternativ för CasinoCoin - - Modify configuration options for Bitcoin - Ändra konfigurationsalternativ för Bitcoin - - - - Show or hide the Bitcoin window - Visa eller göm Bitcoin-fönstret - - - - Export the data in the current tab to a file - Exportera informationen i den nuvarande fliken till en fil - - - - Encrypt or decrypt wallet - Kryptera eller dekryptera plånbok - - - + Backup wallet to another location Säkerhetskopiera plånboken till en annan plats - + Change the passphrase used for wallet encryption Byt lösenord för kryptering av plånbok - + &Debug window &Debug fönster - + Open debugging and diagnostic console Öppna debug- och diagnostikkonsolen - + &Verify message... &Verifiera meddelande... - - Verify a message signature - Verifiera meddelandets signatur + + + CasinoCoin + CasinoCoin - + + Wallet + Plånbok + + + + &Send + &Skicka + + + + &Receive + &Ta emot + + + + &Addresses + &Adresser + + + + &About CasinoCoin + &Om CasinoCoin + + + + &Show / Hide + &Visa / Göm + + + + Show or hide the main Window + Visa eller göm huvudfönstret + + + + Encrypt the private keys that belong to your wallet + Kryptera de privata nycklar som tillhör din plånbok + + + + Sign messages with your CasinoCoin addresses to prove you own them + Signera meddelanden med din CasinoCoinadress för att bevisa att du äger dem + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Verifiera meddelanden för att vara säker på att de var signerade med den specificerade CasinoCoin-adressen + + + &File &Arkiv - + &Settings &Inställningar - + &Help &Hjälp - + Tabs toolbar Verktygsfält för Tabbar - - Actions toolbar - Verktygsfältet för Handlingar - - - - + + [testnet] [testnet] - - - Bitcoin client - Bitcoin-klient + + CasinoCoin client + CasinoCoin-klient - - %n active connection(s) to Bitcoin network - %n aktiv anslutning till Bitcoin-nätverket%n aktiva anslutningar till Bitcoin-nätverket + + %n active connection(s) to CasinoCoin network + %n aktiv anslutning till CasinoCoin-nätverket%n aktiva anslutningar till CasinoCoin-nätverket - - Downloaded %1 blocks of transaction history. - Laddat ner %1 block från transaktionshistoriken. - - - - %n second(s) ago - %n sekund sedan%n sekunder sedan - - - - %n minute(s) ago - %n minut sedan%n minuter sedan - - - - %n hour(s) ago - %n timme sedan%n timmar sedan - - - - %n day(s) ago - %n dag sedan%n dagar sedan + + No block source available... + Ingen block-källa tillgänglig... - + + Processed %1 of %2 (estimated) blocks of transaction history. + Bearbetat %1 av %2 (uppskattade) block av transaktionshistorik. + + + + Processed %1 blocks of transaction history. + Bearbetat %1 block i transaktionshistoriken. + + + + %n hour(s) + %n timme%n timmar + + + + %n day(s) + %n dag%n dagar + + + + %n week(s) + %n vecka%n veckor + + + + %1 behind + %1 efter + + + + Last received block was generated %1 ago. + Senast mottagna block genererades %1 sen. + + + + Transactions after this will not yet be visible. + Transaktioner efter denna kommer inte ännu vara synliga. + + + + Error + Fel + + + + Warning + Varning + + + + Information + Information + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Transaktionen överskrider storleksgränsen. Du kan dock fortfarande skicka den mot en kostnad av %1, som går till noderna som behandlar din transaktion och bidrar till nätverket. Vill du betala denna avgift? + + + Up to date Uppdaterad - + Catching up... Hämtar senaste... - - Last received block was generated %1. - Senast mottagna block genererades %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Transaktionen överskrider storleksgränsen. Du kan dock fortfarande skicka den mot en kostnad av %1. Denna avgift går till noderna som behandlar din transaktion och bidrar till nätverket. Vill du betala denna avgift? - - - + Confirm transaction fee Bekräfta överföringsavgift - + Sent transaction Transaktion skickad - + Incoming transaction Inkommande transaktion - + Date: %1 Amount: %2 Type: %3 @@ -582,538 +649,485 @@ Adress: %4 - + + + URI handling + URI hantering + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI går inte att tolkas! Detta kan orsakas av en ogiltig CasinoCoin-adress eller felaktiga URI parametrar. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Denna plånbok är <b>krypterad</b> och för närvarande <b>olåst</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> Denna plånbok är <b>krypterad</b> och för närvarande <b>låst</b> - - Backup Wallet - Säkerhetskopiera Plånbok - - - - Wallet Data (*.dat) - Plånboks-data (*.dat) - - - - Backup Failed - Säkerhetskopiering misslyckades - - - - There was an error trying to save the wallet data to the new location. - Det inträffade ett fel när plånboken skulle sparas till den nya platsen. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Ett allvarligt fel har uppstått. Bitcoin kan inte längre köras säkert och kommer att avslutas. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ett allvarligt fel har uppstått. CasinoCoin kan inte längre köras säkert och kommer att avslutas. ClientModel - + Network Alert Nätverkslarm - - DisplayOptionsPage - - - Display - Visa - - - - default - standard - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - Användargränssnittets språk kan ställas in här. Denna inställning träder i kraft efter en omstart av Bitcoin. - - - - User Interface &Language: - Användargränssnittets &Språk: - - - - &Unit to show amounts in: - &Måttenhet att visa belopp i: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Välj en måttenhet att visa när du skickar mynt - - - - &Display addresses in transaction list - &Visa adresser i transaktionslistan - - - - Whether to show Bitcoin addresses in the transaction list - Anger om Bitcoin-adresser skall visas i transaktionslistan - - - - Warning - Varning - - - - This setting will take effect after restarting Bitcoin. - Denna inställning träder i kraft efter en omstart av Bitcoin. - - EditAddressDialog - + Edit Address Redigera Adress - + &Label &Etikett - + The label associated with this address book entry Den etikett som är associerad med detta adressboksinlägg - + &Address &Adress - + The address associated with this address book entry. This can only be modified for sending addresses. Adressen som är associerad med detta adressboksinlägg. Detta kan enbart ändras för sändande adresser. - + New receiving address Ny mottagaradress - + New sending address Ny avsändaradress - + Edit receiving address Redigera mottagaradress - + Edit sending address Redigera avsändaradress - + The entered address "%1" is already in the address book. Den angivna adressen "%1" finns redan i adressboken. - - The entered address "%1" is not a valid Bitcoin address. - Den angivna adressen "%1" är inte en giltig Bitcoin-adress. + + The entered address "%1" is not a valid CasinoCoin address. + Den angivna adressen "%1" är inte en giltig CasinoCoin-adress. - + Could not unlock wallet. Plånboken kunde inte låsas upp. - + New key generation failed. Misslyckades med generering av ny nyckel. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version version - + Usage: Användning: - - options - alternativ + + command-line options + kommandoradsalternativ - + UI options UI alternativ - + Set language, for example "de_DE" (default: system locale) - Ändra språk, till exempel "de_DE" (standard: systemets språk) + Ändra språk, till exempel "de_DE" (förvalt: systemets språk) - + Start minimized Starta som minimerad - + Show splash screen on startup (default: 1) - Visa startbilden vid uppstart (standard: 1) - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Frigör block- och adressdatabaser vid nedstängning. Detta innebär att de kan flyttas till en annan data katalog, men det saktar ner avstängningen. Plånboken är alltid frigjord. - - - - Pay transaction &fee - Betala överförings&avgift - - - - Main - Allmänt - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Valfri transaktionsavgift per kB som ser till att dina transaktioner behandlas snabbt. De flesta transaktioner är 1 kB. Avgift 0.01 rekommenderas. - - - - &Start Bitcoin on system login - &Starta Bitcoin vid systemstart - - - - Automatically start Bitcoin after logging in to the system - Starta Bitcoin automatiskt efter inloggning - - - - &Detach databases at shutdown - &Frigör databaser vid nedstängning - - - - MessagePage - - - Sign Message - Signera meddelande - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Du kan signera meddelanden med dina adresser för att bevisa att du äger dem. Var försiktig med vad du signerar eftersom phising-attacker kan försöka få dig att skriva över din identitet till någon annan. Signera bara väldetaljerade påståenden du kan gå i god för. - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adressen att signera meddelandet med (t.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Välj adress från adressboken - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Klistra in adress från Urklipp - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Skriv in meddelandet du vill signera här - - - - Copy the current signature to the system clipboard - Kopiera signaturen till systemets Urklipp - - - - &Copy Signature - &Kopiera signatur - - - - Reset all sign message fields - Rensa alla fält - - - - Clear &All - Rensa &alla - - - - Click "Sign Message" to get signature - Klicka "Signera Meddelande" för att få en signatur - - - - Sign a message to prove you own this address - Signera ett meddelande för att bevisa att du äger denna adress - - - - &Sign Message - &Signera meddelande - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Ange en Bitcoin-adress (t.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Fel vid signering - - - - %1 is not a valid address. - %1 är ingen giltig adress. - - - - %1 does not refer to a key. - %1 refererar inte till en nyckel. - - - - Private key for %1 is not available. - Privata nyckeln för %1 är inte tillgänglig. - - - - Sign failed - Signering misslyckades - - - - NetworkOptionsPage - - - Network - Nätverk - - - - Map port using &UPnP - Tilldela port med hjälp av &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Öppna automatiskt Bitcoin-klientens port på routern. Detta fungerar endast om din router har UPnP aktiverat. - - - - &Connect through SOCKS4 proxy: - &Anslut genom SOCKS4-proxy: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Anslut till Bitcoin-nätverket genom en SOCKS4-proxy (t.ex. när du ansluter genom Tor) - - - - Proxy &IP: - Proxy-&IP: - - - - &Port: - &Port: - - - - IP address of the proxy (e.g. 127.0.0.1) - Proxyns IP-adress (t.ex. 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Proxyns port (t.ex. 1234) + Visa startbilden vid uppstart (förvalt: 1) OptionsDialog - + Options Alternativ + + + &Main + &Allmänt + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Valfri transaktionsavgift per kB som ser till att dina transaktioner behandlas snabbt. De flesta transaktioner är 1 kB. + + + + Pay transaction &fee + Betala överförings&avgift + + + + Automatically start CasinoCoin after logging in to the system. + Starta CasinoCoin automatiskt efter inloggning. + + + + &Start CasinoCoin on system login + &Starta CasinoCoin vid systemstart + + + + Reset all client options to default. + Återställ alla klient inställningar till förvalen. + + + + &Reset Options + &Återställ Alternativ + + + + &Network + &Nätverk + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Öppna automatiskt CasinoCoin-klientens port på routern. Detta fungerar endast om din router har UPnP aktiverat. + + + + Map port using &UPnP + Tilldela port med hjälp av &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Anslut till CasinoCoin-nätverket genom en SOCKS-proxy (t.ex. när du ansluter genom Tor). + + + + &Connect through SOCKS proxy: + &Anslut genom SOCKS-proxy: + + + + Proxy &IP: + Proxy-&IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + Proxyns IP-adress (t.ex. 127.0.0.1) + + + + &Port: + &Port: + + + + Port of the proxy (e.g. 9050) + Proxyns port (t.ex. 9050) + + + + SOCKS &Version: + SOCKS &Version: + + + + SOCKS version of the proxy (e.g. 5) + SOCKS version av proxyn (t.ex. 5) + + + + &Window + &Fönster + + + + Show only a tray icon after minimizing the window. + Visa endast en systemfältsikon vid minimering. + + + + &Minimize to the tray instead of the taskbar + &Minimera till systemfältet istället för aktivitetsfältet + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimera applikationen istället för att stänga ner den när fönstret stängs. Detta innebär att programmet fotrsätter att köras tills du väljer Avsluta i menyn. + + + + M&inimize on close + M&inimera vid stängning + + + + &Display + &Visa + + + + User Interface &language: + Användargränssnittets &språk: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Användargränssnittets språk kan ställas in här. Denna inställning träder i kraft efter en omstart av CasinoCoin. + + + + &Unit to show amounts in: + &Måttenhet att visa belopp i: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Välj en måttenhet att visa när du skickar mynt. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Anger om CasinoCoin-adresser skall visas i transaktionslistan. + + + + &Display addresses in transaction list + &Visa adresser i transaktionslistan + + + + &OK + &OK + + + + &Cancel + &Avbryt + + + + &Apply + &Verkställ + + + + default + standard + + + + Confirm options reset + Bekräfta att alternativen ska återställs + + + + Some settings may require a client restart to take effect. + Vissa inställningar kan behöva en omstart av klienten för att börja gälla. + + + + Do you want to proceed? + Vill du fortsätta? + + + + + Warning + Varning + + + + + This setting will take effect after restarting CasinoCoin. + Denna inställning träder i kraft efter en omstart av CasinoCoin. + + + + The supplied proxy address is invalid. + Den medföljande proxy adressen är ogiltig. + OverviewPage - + Form Formulär - - - 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. - Den visade informationen kan vara inaktuell. Plånboken synkroniseras automatiskt med Bitcoin-nätverket efter att anslutningen är upprättad, men denna process har inte slutförts ännu. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Den visade informationen kan vara inaktuell. Plånboken synkroniseras automatiskt med CasinoCoin-nätverket efter att anslutningen är upprättad, men denna process har inte slutförts ännu. - + Balance: Saldo: - - Number of transactions: - Antal transaktioner: - - - + Unconfirmed: Obekräftade: - + Wallet Plånbok - + + Immature: + Omogen: + + + + Mined balance that has not yet matured + Den genererade balansen som ännu inte har mognat + + + <b>Recent transactions</b> <b>Nyligen genomförda transaktioner</b> - + Your current balance Ditt nuvarande saldo - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Totalt antal transaktioner som ännu inte bekräftats, och som ännu inte räknas med i aktuellt saldo - - Total number of transactions in wallet - Totalt antal transaktioner i plånboken - - - - + + out of sync osynkroniserad + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + Kan inte starta casinocoin: klicka-och-betala handhavare + + QRCodeDialog - + QR Code Dialog QR-kod dialogruta - - QR Code - QR-kod - - - + Request Payment Begär Betalning - + Amount: Belopp: - - BTC - BTC - - - + Label: Etikett: - + Message: Meddelande: - + &Save As... &Spara som... - + Error encoding URI into QR Code. Fel vid skapande av QR-kod från URI. - + + The entered amount is invalid, please check. + Det angivna beloppet är ogiltigt, vänligen kontrollera. + + + Resulting URI too long, try to reduce the text for label / message. URI:n är för lång, försöka minska texten för etikett / meddelande. - + Save QR Code Spara QR-kod - + PNG Images (*.png) PNG-bilder (*.png) @@ -1121,125 +1135,146 @@ Adress: %4 RPCConsole - - Bitcoin debug window - Bitcoin debug fönster - - - + Client name Klientnamn - - - - - - - - - + + + + + + + + + + N/A ej tillgänglig - + Client version Klient-version - + &Information &Information - - Client - Klient + + Using OpenSSL version + Använder OpenSSL version - + Startup time Uppstartstid - + Network Nätverk - + Number of connections Antalet anslutningar - + On testnet På testnet - + Block chain Blockkedja - + Current number of blocks Aktuellt antal block - + Estimated total blocks Beräknade totala block - + Last block time Sista blocktid - - Debug logfile - Debugloggfil - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - Öppna Bitcoin debug-loggfilen som finns i datakatalogen. Detta kan ta några sekunder för stora loggfiler. - - - + &Open &Öppna - + + Command-line options + Kommandoradsalternativ + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Visa CasinoCoin-Qt hjälpmeddelande för att få en lista med möjliga CasinoCoin kommandoradsalternativ. + + + + &Show + &Visa + + + &Console &Konsol - + Build date Kompileringsdatum - + + CasinoCoin - Debug window + CasinoCoin - Debug fönster + + + + CasinoCoin Core + CasinoCoin Kärna + + + + Debug log file + Debugloggfil + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Öppna CasinoCoin debug-loggfilen som finns i datakatalogen. Detta kan ta några sekunder för stora loggfiler. + + + Clear console Rensa konsollen - - Welcome to the Bitcoin RPC console. - Välkommen till Bitcoin RPC-konsollen. + + Welcome to the CasinoCoin RPC console. + Välkommen till CasinoCoin RPC-konsollen. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Använd upp- och ner-pilarna för att navigera i historiken, och <b>Ctrl-L</b> för att rensa skärmen. - + Type <b>help</b> for an overview of available commands. Skriv <b>help</b> för en översikt av alla kommandon. @@ -1247,109 +1282,109 @@ Adress: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Skicka pengar - + Send to multiple recipients at once Skicka till flera mottagare samtidigt - - &Add Recipient - &Lägg till mottagare + + Add &Recipient + Lägg till &mottagare - + Remove all transaction fields Ta bort alla transaktions-fält - + Clear &All Rensa &alla - + Balance: Balans: - + 123.456 BTC 123,456 BTC - + Confirm the send action Bekräfta sändordern - - &Send + + S&end &Skicka - + <b>%1</b> to %2 (%3) <b>%1</b> till %2 (%3) - + Confirm send coins Bekräfta skickade mynt - + Are you sure you want to send %1? Är du säker på att du vill skicka %1? - + and och - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Mottagarens adress är inte giltig, vänligen kontrollera igen. - + The amount to pay must be larger than 0. Det betalade beloppet måste vara större än 0. - + The amount exceeds your balance. Värdet överstiger ditt saldo. - + The total exceeds your balance when the %1 transaction fee is included. Totalvärdet överstiger ditt saldo när transaktionsavgiften %1 är pålagd. - + Duplicate address found, can only send to each address once per send operation. Dubblett av adress funnen, kan bara skicka till varje adress en gång per sändning. - - Error: Transaction creation failed. - Fel: Transaktionen gick inte att skapa. + + Error: Transaction creation failed! + Fel: Transaktionen gick inte att skapa! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. Fel: Transaktionen avslogs. Detta kan hända om några av mynten i plånboken redan spenderats, t.ex om du använt en kopia av wallet.dat och mynt spenderades i kopian men inte markerats som spenderas här. @@ -1357,217 +1392,456 @@ Adress: %4 SendCoinsEntry - + Form Formulär - + A&mount: &Belopp: - + Pay &To: Betala &Till: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adressen som betalningen skall skickas till (t.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Ange ett namn för den här adressen och lägg till den i din adressbok - + &Label: &Etikett: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Adressen som betalningen skall skickas till (t.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Välj adress från adresslistan - + Alt+A Alt+A - + Paste address from clipboard Klistra in adress från Urklipp - + Alt+P Alt+P - + Remove this recipient Ta bort denna mottagare - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Ange en Bitcoin-adress (t.ex. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Ange en CasinoCoin-adress (t.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signaturer - Signera / Verifiera ett Meddelande + + + + &Sign Message + &Signera Meddelande + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Du kan signera meddelanden med dina adresser för att bevisa att du äger dem. Var försiktig med vad du signerar eftersom phising-attacker kan försöka få dig att skriva över din identitet till någon annan. Signera bara väldetaljerade påståenden du kan gå i god för. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adressen att signera meddelandet med (t.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Välj en adress från adressboken + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Klistra in adress från Urklipp + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Skriv in meddelandet du vill signera här + + + + Signature + Signatur + + + + Copy the current signature to the system clipboard + Kopiera signaturen till systemets Urklipp + + + + Sign the message to prove you own this CasinoCoin address + Signera meddelandet för att bevisa att du äger denna adress + + + + Sign &Message + Signera &Meddelande + + + + Reset all sign message fields + Rensa alla fält + + + + + Clear &All + Rensa &alla + + + + &Verify Message + &Verifiera Meddelande + + + + Enter the signing 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. + Skriv in din adress, meddelande (se till att du kopierar radbrytningar, mellanslag, tabbar, osv. exakt) och signatur nedan för att verifiera meddelandet. Var noga med att inte läsa in mer i signaturen än vad som finns i det signerade meddelandet, för att undvika att luras av en man-in-the-middle attack. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Adressen som meddelandet var signerat med (t.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Verifiera meddelandet för att vara säker på att den var signerad med den angivna CasinoCoin-adressen + + + + Verify &Message + Verifiera &Meddelande + + + + Reset all verify message fields + Rensa alla fält + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Ange en CasinoCoin-adress (t.ex. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Klicka "Signera Meddelande" för att få en signatur + + + + Enter CasinoCoin signature + Ange CasinoCoin-signatur + + + + + The entered address is invalid. + Den angivna adressen är ogiltig. + + + + + + + Please check the address and try again. + Vad god kontrollera adressen och försök igen. + + + + + The entered address does not refer to a key. + Den angivna adressen refererar inte till en nyckel. + + + + Wallet unlock was cancelled. + Upplåsningen av plånboken avbröts. + + + + Private key for the entered address is not available. + Privata nyckel för den angivna adressen är inte tillgänglig. + + + + Message signing failed. + Signeringen av meddelandet misslyckades. + + + + Message signed. + Meddelandet är signerat. + + + + The signature could not be decoded. + Signaturen kunde inte avkodas. + + + + + Please check the signature and try again. + Kontrollera signaturen och försök igen. + + + + The signature did not match the message digest. + Signaturen matchade inte meddelandesammanfattningen. + + + + Message verification failed. + Meddelandet verifikation misslyckades. + + + + Message verified. + Meddelandet är verifierad. + + + + SplashScreen + + + The CasinoCoin developers + CasinoCoin-utvecklarna + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - Öppen för %1 block - - - + Open until %1 Öppet till %1 - - %1/offline? - %1/nerkopplad? + + %1/offline + %1/nerkopplad - + %1/unconfirmed %1/obekräftade - + %1 confirmations %1 bekräftelser - - <b>Status:</b> - <b>Status:</b> + + Status + Status + + + + , broadcast through %n node(s) + , sänd genom %n nod, sänd genom %n noder - + + Date + Datum + + + + Source + Källa + + + + Generated + Genererad + + + + + From + Från + + + + + + To + Till + + + + + own address + egen adress + + + + label + etikett + + + + + + + + Credit + Kredit + + + + matures in %n more block(s) + mognar om %n blockmognar om %n fler block + + + + not accepted + inte accepterad + + + + + + + Debit + Belasta + + + + Transaction fee + Transaktionsavgift + + + + Net amount + Nettobelopp + + + + Message + Meddelande + + + + Comment + Kommentar + + + + Transaction ID + Transaktions-ID + + + + Generated coins must mature 120 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. + Genererade mynt måste vänta 120 block innan de kan användas. När du skapade detta block sändes det till nätverket för att läggas till i blockkedjan. Om blocket inte kommer in i kedjan kommer det att ändras till "accepteras inte" och kommer ej att gå att spendera. Detta kan ibland hända om en annan nod genererar ett block nästan samtidigt som dig. + + + + Debug information + Debug information + + + + Transaction + Transaktion + + + + Inputs + Inputs + + + + Amount + Mängd + + + + true + sant + + + + false + falsk + + + , has not been successfully broadcast yet , har inte lyckats skickas ännu - - - , broadcast through %1 node - , sänd genom %1 nod + + + Open for %n more block(s) + Öppet för %n mer blockÖppet för %n mer block - - , broadcast through %1 nodes - , sänd genom %1 noder - - - - <b>Date:</b> - <b>Datum:</b> - - - - <b>Source:</b> Generated<br> - <b>Källa:</b> Genererade<br> - - - - - <b>From:</b> - <b>Från:</b> - - - + unknown okänd - - - - - <b>To:</b> - <b>Till:</b> - - - - (yours, label: - (din, etikett: - - - - (yours) - (dina) - - - - - - - <b>Credit:</b> - <b>Kredit:</b> - - - - (%1 matures in %2 more blocks) - (%1 mognar om %2 block) - - - - (not accepted) - (inte accepterad) - - - - - - <b>Debit:</b> - <b>Debet:</b> - - - - <b>Transaction fee:</b> - <b>Transaktionsavgift:</b> - - - - <b>Net amount:</b> - <b>Nettobelopp:</b> - - - - Message: - Meddelande: - - - - Comment: - Kommentar: - - - - Transaction ID: - Transaktions-ID: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Genererade mynt måste vänta 120 block innan de kan användas. När du skapade detta block sändes det till nätverket för att läggas till i blockkedjan. Om blocket inte kommer in i kedjan kommer det att ändras till "accepteras inte" och kommer ej att gå att spendera. Detta kan ibland hända om en annan nod genererar ett block nästan samtidigt som dig. - TransactionDescDialog - + Transaction details Transaktionsdetaljer - + This pane shows a detailed description of the transaction Den här panelen visar en detaljerad beskrivning av transaktionen @@ -1575,117 +1849,117 @@ Adress: %4 TransactionTableModel - + Date Datum - + Type Typ - + Address Adress - + Amount Mängd - - Open for %n block(s) - Öppen i %n blockÖppen i %n block + + Open for %n more block(s) + Öppet för %n mer blockÖppet för %n mer block - + Open until %1 Öppet till %1 - + Offline (%1 confirmations) Offline (%1 bekräftelser) - + Unconfirmed (%1 of %2 confirmations) Obekräftad (%1 av %2 bekräftelser) - + Confirmed (%1 confirmations) Bekräftad (%1 bekräftelser) - - Mined balance will be available in %n more blocks - Genererat belopp kommer bli tillgängligt om %n blockGenererat belopp kommer bli tillgängligt om %n block + + Mined balance will be available when it matures in %n more block(s) + Genererade balansen kommer att finnas tillgänglig när den mognar om %n mer blockGenererade balansen kommer att finnas tillgänglig när den mognar om %n fler block - + This block was not received by any other nodes and will probably not be accepted! Det här blocket togs inte emot av några andra noder och kommer antagligen inte att bli godkänt. - + Generated but not accepted Genererad men inte accepterad - + Received with Mottagen med - + Received from Mottaget från - + Sent to Skickad till - + Payment to yourself Betalning till dig själv - + Mined Genererade - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. Transaktionsstatus. Håll muspekaren över för att se antal bekräftelser. - + Date and time that the transaction was received. Tidpunkt då transaktionen mottogs. - + Type of transaction. Transaktionstyp. - + Destination address of transaction. Transaktionens destinationsadress. - + Amount removed from or added to balance. Belopp draget eller tillagt till balans. @@ -1693,817 +1967,967 @@ Adress: %4 TransactionView - - + + All Alla - + Today Idag - + This week Denna vecka - + This month Denna månad - + Last month Föregående månad - + This year Det här året - + Range... Period... - + Received with Mottagen med - + Sent to Skickad till - + To yourself Till dig själv - + Mined Genererade - + Other Övriga - + Enter address or label to search Sök efter adress eller etikett - + Min amount Minsta mängd - + Copy address Kopiera adress - + Copy label Kopiera etikett - + Copy amount Kopiera belopp - + + Copy transaction ID + Kopiera transaktions ID + + + Edit label Ändra etikett - + Show transaction details Visa transaktionsdetaljer - + Export Transaction Data Exportera Transaktionsdata - + Comma separated file (*.csv) Kommaseparerad fil (*. csv) - + Confirmed Bekräftad - + Date Datum - + Type Typ - + Label Etikett - + Address Adress - + Amount Mängd - + ID ID - + Error exporting Fel vid export - + Could not write to file %1. Kunde inte skriva till filen %1. - + Range: Intervall: - + to till - - VerifyMessageDialog - - - Verify Signed Message - Verifiera Signerat Meddelande - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - Skriv meddelandet och signaturen nedan (var noga med att kopiera rätt nyradstecken, mellanslag, tabbar och andra osynliga tecken) för att erhålla Bitcoin-adressen som användes för att signera meddelandet. - - - - Verify a message and obtain the Bitcoin address used to sign the message - Verifiera ett meddelande och erhåll Bitcoin-adressen som användes för att signera meddelandet - - - - &Verify Message - &Verifiera Meddelande - - - - Copy the currently selected address to the system clipboard - Kopiera den markerade adressen till systemets Urklipp - - - - &Copy Address - &Kopiera adress - - - - Reset all verify message fields - Rensa alla fält - - - - Clear &All - Rensa &alla - - - - Enter Bitcoin signature - Ange Bitcoin-signatur - - - - Click "Verify Message" to obtain address - Klicka på "Verifiera meddelande" för att få adressen - - - - - Invalid Signature - Ogiltig Signatur - - - - The signature could not be decoded. Please check the signature and try again. - Signaturen kunde inte avkodas. Kontrollera signaturen och försök igen. - - - - The signature did not match the message digest. Please check the signature and try again. - Signaturen matchade inte meddelandesammanfattningen. Kontrollera signaturen och försök igen. - - - - Address not found in address book. - Adressen hittas ej i adressboken. - - - - Address found in address book: %1 - Adressen hittades i adressboken: %1 - - WalletModel - - Sending... - Skickar... + + Send Coins + Skicka pengar - WindowOptionsPage + WalletView - - Window - Fönster + + &Export + &Exportera - - &Minimize to the tray instead of the taskbar - &Minimera till systemfältet istället för aktivitetsfältet + + Export the data in the current tab to a file + Exportera informationen i den nuvarande fliken till en fil - - Show only a tray icon after minimizing the window - Visa endast en systemfältsikon vid minimering + + Backup Wallet + Säkerhetskopiera Plånbok - - M&inimize on close - M&inimera vid stängning + + Wallet Data (*.dat) + Plånboks-data (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Minimera applikationen istället för att stänga ner den när fönstret stängs. Detta innebär att programmet fotrsätter att köras tills du väljer Avsluta i menyn. + + Backup Failed + Säkerhetskopiering misslyckades + + + + There was an error trying to save the wallet data to the new location. + Det inträffade ett fel när plånboken skulle sparas till den nya platsen. + + + + Backup Successful + Säkerhetskopiering lyckades + + + + The wallet data was successfully saved to the new location. + Plånbokens data har sparats till den nya platsen. bitcoin-core - - Bitcoin version - Bitcoin version + + CasinoCoin version + CasinoCoin version - + Usage: Användning: - - Send command to -server or bitcoind - Skicka kommando till -server eller bitcoind + + Send command to -server or casinocoind + Skicka kommando till -server eller casinocoind - + List commands Lista kommandon - + Get help for a command Få hjälp med ett kommando - + Options: Inställningar: - - Specify configuration file (default: bitcoin.conf) - Ange konfigurationsfil (standard: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Ange konfigurationsfil (förvalt: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Ange pid fil (standard: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Ange pid fil (förvalt: casinocoind.pid) - - Generate coins - Generera mynt - - - - Don't generate coins - Generera inte mynt - - - + Specify data directory Ange katalog för data - + Set database cache size in megabytes (default: 25) - Sätt databas cache storleken i megabyte (standard: 25) + Sätt databas cache storleken i megabyte (förvalt: 25) - - Set database disk log size in megabytes (default: 100) - Sätt databasens loggfil storlek i megabyte (standard: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Lyssna efter anslutningar på <port> (förvalt: 47950 eller testnet: 17950) - - Specify connection timeout (in milliseconds) - Ange timeout för uppkoppling (i millisekunder) - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Lyssna efter anslutningar på <port> (förval: 8333 eller testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) - Ha som mest <n> anslutningar till andra klienter (förval: 125) + Ha som mest <n> anslutningar till andra klienter (förvalt: 125) - - Connect only to the specified node - Koppla enbart upp till den specifierade noden - - - + Connect to a node to retrieve peer addresses, and disconnect Anslut till en nod för att hämta klientadresser, och koppla från - + Specify your own public address Ange din egen publika adress - - Only connect to nodes in network <net> (IPv4 or IPv6) - Anslut enbart till noder i nätverket <net> (IPv4 eller IPv6) - - - - Try to discover public IP address (default: 1) - Försök att upptäcka den publika IP-adressen (standard: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - Bind till given adress. Använd [värd]:port notation för IPv6 - - - + Threshold for disconnecting misbehaving peers (default: 100) - Tröskelvärde för att koppla ifrån klienter som missköter sig (förval: 100) + Tröskelvärde för att koppla ifrån klienter som missköter sig (förvalt: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - Antal sekunder att hindra klienter som missköter sig från att ansluta (förval: 86400) + Antal sekunder att hindra klienter som missköter sig från att ansluta (förvalt: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maximal buffert för mottagning per anslutning, <n>*1000 byte (förval: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Ett fel uppstod vid upprättandet av RPC port %u för att lyssna på IPv4: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maximal buffert för sändning per anslutning, <n>*1000 byte (förval: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Lyssna på JSON-RPC-anslutningar på <port> (förvalt: 47970 eller testnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - Frigör block- och adressdatabaser vid nedstängning. Detta ökar tiden för nedstängning (standard: 0) - - - + Accept command line and JSON-RPC commands Tillåt kommandon från kommandotolken och JSON-RPC-kommandon - + Run in the background as a daemon and accept commands Kör i bakgrunden som tjänst och acceptera kommandon - + Use the test network Använd testnätverket - - Output extra debugging information - Skriv ut extra felsökningsinformation + + Accept connections from outside (default: 1 if no -proxy or -connect) + Acceptera anslutningar utifrån (förvalt: 1 om ingen -proxy eller -connect) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, du behöver sätta ett rpclösensord i konfigurationsfilen: +%s +Det är rekommenderat att använda följande slumpade lösenord: +rpcuser=casinocoinrpc +rpcpassword=%s +(du behöver inte komma ihåg lösenordet) +Användarnamnet och lösenordet FÅR INTE bara detsamma. +Om filen inte existerar, skapa den med enbart ägarläsbara filrättigheter. +Det är också rekommenderat att sätta alertnotify så du meddelas om problem; +till exempel: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Ett fel uppstod vid upprättandet av RPC port %u för att lyssna på IPv6, faller tillbaka till IPV4: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Bind till given adress och lyssna alltid på den. Använd [värd]:port notation för IPv6 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + Kan inte låsa data-mappen %s. CasinoCoin körs förmodligen redan. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Fel: Transaktionen avslogs! Detta kan hända om några av mynten i plånboken redan spenderats, t.ex om du använt en kopia av wallet.dat och mynt spenderades i kopian men inte markerats som spenderas här. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Fel: Denna transaktion kräver en transaktionsavgift på minst %s på grund av dess storlek, komplexitet, eller användning av senast mottagna casinocoins! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + Exekvera kommando när ett relevant meddelande är mottagen (%s i cmd är utbytt med ett meddelande) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Exekvera kommando när en plånbokstransaktion ändras (%s i cmd är ersatt av TxID) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Sätt den maximala storleken av hög-prioriterade/låg-avgifts transaktioner i byte (förvalt: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Detta är ett förhands testbygge - använd på egen risk - använd inte för mining eller handels applikationer + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Varning: -paytxfee är satt väldigt hög! Detta är avgiften du kommer betala för varje transaktion. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Varning: Visade transaktioner kanske inte är korrekt! Du kan behöva uppgradera, eller andra noder kan behöva uppgradera. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Varning: Vänligen kolla så att din dators datum och tid är korrekt! Om din klocka går fel kommer CasinoCoin inte fungera korrekt. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Varning: fel vid läsning av wallet.dat! Alla nycklar lästes korrekt, men transaktionsdatan eller adressbokens poster kanske saknas eller är felaktiga. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Varning: wallet.dat korrupt, datan har räddats! Den ursprungliga wallet.dat har sparas som wallet.{timestamp}.bak i %s; om ditt saldo eller transaktioner är felaktiga ska du återställa från en säkerhetskopia. + + + + Attempt to recover private keys from a corrupt wallet.dat + Försök att rädda de privata nycklarna från en korrupt wallet.dat + + + + Block creation options: + Block skapande inställningar: + + + + Connect only to the specified node(s) + Koppla enbart upp till den/de specificerade noden/noder + + + + Corrupted block database detected + Korrupt blockdatabas har upptäckts + + + + Discover own IP address (default: 1 when listening and no -externalip) + Hitta egen IP-adress (förvalt: 1 under lyssning och utan -externalip) + + + + Do you want to rebuild the block database now? + Vill du bygga om blockdatabasen nu? + + + + Error initializing block database + Fel vid initiering av blockdatabasen + + + + Error initializing wallet database environment %s! + Fel vid initiering av plånbokens databasmiljö %s! + + + + Error loading block database + Fel vid inläsning av blockdatabasen + + + + Error opening block database + Fel vid öppning av blockdatabasen + + + + Error: Disk space is low! + Fel: Hårddiskutrymme är lågt! + + + + Error: Wallet locked, unable to create transaction! + Fel: Plånboken är låst, det går ej att skapa en transaktion! + + + + Error: system error: + Fel: systemfel: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Misslyckades att lyssna på någon port. Använd -listen=0 om du vill detta. + + + + Failed to read block info + Misslyckades att läsa blockinformation + + + + Failed to read block + Misslyckades att läsa blocket + + + + Failed to sync block index + Misslyckades att synkronisera blockindex + + + + Failed to write block index + Misslyckades att skriva blockindex + + + + Failed to write block info + Misslyckades att skriva blockinformation + + + + Failed to write block + Misslyckades att skriva blocket + + + + Failed to write file info + Misslyckades att skriva filinformation + + + + Failed to write to coin database + Misslyckades att skriva till myntdatabas + + + + Failed to write transaction index + Misslyckades att skriva transaktionsindex + + + + Failed to write undo data + Misslyckades att skriva ångradata + + + + Find peers using DNS lookup (default: 1 unless -connect) + Sök efter klienter med DNS sökningen (förvalt: 1 om inte -connect) + + + + Generate coins (default: 0) + Generera mynt (förvalt: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Hur många block att kontrollera vid uppstart (standardvärde: 288, 0 = alla) + + + + How thorough the block verification is (0-4, default: 3) + Hur grundlig blockverifikationen är (0-4, förvalt: 3) + + + + Not enough file descriptors available. + Inte tillräckligt med filbeskrivningar tillgängliga. + + + + Rebuild block chain index from current blk000??.dat files + Återskapa blockkedjans index från nuvarande blk000??.dat filer + + + + Set the number of threads to service RPC calls (default: 4) + Ange antalet trådar för att hantera RPC anrop (standard: 4) + + + + Verifying blocks... + Verifierar block... + + + + Verifying wallet... + Verifierar plånboken... + + + + Imports blocks from external blk000??.dat file + Importerar block från extern blk000??.dat fil + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Ange antalet skriptkontrolltrådar (upp till 16, 0 = auto, <0 = lämna så många kärnor lediga, förval: 0) + + + + Information + Information + + + + Invalid -tor address: '%s' + Ogiltig -tor adress: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ogiltigt belopp för -minrelaytxfee=<belopp>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ogiltigt belopp för -mintxfee=<belopp>: '%s' + + + + Maintain a full transaction index (default: 0) + Upprätthåll ett fullständigt transaktionsindex (förval: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maximal buffert för mottagning per anslutning, <n>*1000 byte (förvalt: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maximal buffert för sändning per anslutning, <n>*1000 byte (förvalt: 5000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Acceptera bara blockkedjans matchande inbyggda kontrollpunkter (förvalt: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Anslut enbart till noder i nätverket <net> (IPv4, IPv6 eller Tor) + + + + Output extra debugging information. Implies all other -debug* options + Skriv ut extra felsökningsinformation. Gäller alla andra -debug* alternativ + + + + Output extra network debugging information + Skriv ut extra felsökningsinformation om nätverk + + + Prepend debug output with timestamp Skriv ut tid i felsökningsinformationen - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL-inställningar: (se CasinoCoin-wikin för SSL-setup instruktioner) + + + + Select the version of socks proxy to use (4-5, default: 5) + Välj socks-proxy version att använda (4-5, förvalt: 5) + + + Send trace/debug info to console instead of debug.log file Skicka trace-/debuginformation till terminalen istället för till debug.log - + Send trace/debug info to debugger Skicka trace-/debuginformation till debugger - + + Set maximum block size in bytes (default: 250000) + Sätt maximal blockstorlek i byte (förvalt: 250000) + + + + Set minimum block size in bytes (default: 0) + Sätt minsta blockstorlek i byte (förvalt: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Krymp debug.log filen vid klient start (förvalt: 1 vid ingen -debug) + + + + Signing transaction failed + Signering av transaktion misslyckades + + + + Specify connection timeout in milliseconds (default: 5000) + Ange timeout för uppkoppling i millisekunder (förvalt: 5000) + + + + System error: + Systemfel: + + + + Transaction amount too small + Transaktions belopp för liten + + + + Transaction amounts must be positive + Transaktionens belopp måste vara positiva + + + + Transaction too large + Transaktionen är för stor + + + + Use UPnP to map the listening port (default: 0) + Använd UPnP för att mappa den lyssnande porten (förvalt: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Använd UPnP för att mappa den lyssnande porten (förvalt: 1 under lyssning) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Använd en proxy för att nå tor (förvalt: samma som -proxy) + + + Username for JSON-RPC connections Användarnamn för JSON-RPC-anslutningar - + + Warning + Varning + + + + Warning: This version is obsolete, upgrade required! + Varning: denna version är föråldrad, uppgradering krävs! + + + + You need to rebuild the databases using -reindex to change -txindex + Du måste återskapa databaserna med -reindex för att ändra -txindex + + + + wallet.dat corrupt, salvage failed + wallet.dat korrupt, räddning misslyckades + + + Password for JSON-RPC connections Lösenord för JSON-RPC-anslutningar - - Listen for JSON-RPC connections on <port> (default: 8332) - Lyssna på JSON-RPC-anslutningar på <port> (förval: 8332) - - - + Allow JSON-RPC connections from specified IP address Tillåt JSON-RPC-anslutningar från specifika IP-adresser - + Send commands to node running on <ip> (default: 127.0.0.1) - Skicka kommandon till klient på <ip> (förval: 127.0.0.1) + Skicka kommandon till klient på <ip> (förvalt: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - Exekvera kommando när bästa blocket ändras (%s i cmd är utbytt av blockhash) + Exekvera kommando när det bästa blocket ändras (%s i cmd är utbytt av blockhash) - + Upgrade wallet to latest format Uppgradera plånboken till senaste formatet - + Set key pool size to <n> (default: 100) - Sätt storleken på nyckelpoolen till <n> (förval: 100) + Sätt storleken på nyckelpoolen till <n> (förvalt: 100) - + Rescan the block chain for missing wallet transactions - Sök i block-kedjan efter saknade wallet transaktioner + Sök i blockkedjan efter saknade plånboks transaktioner - - How many blocks to check at startup (default: 2500, 0 = all) - Hur många block att kontrollera vid uppstart (standardvärde: 2500, 0 = alla) - - - - How thorough the block verification is (0-6, default: 1) - Hur grundlig blockverifikationen är (0-6, standardvärde: 1) - - - - Imports blocks from external blk000?.dat file - Inporterar block från extern blk000?.dat fil - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL-inställningar: (se Bitcoin-wikin för instruktioner) - - - + Use OpenSSL (https) for JSON-RPC connections Använd OpenSSL (https) för JSON-RPC-anslutningar - + Server certificate file (default: server.cert) - Serverns certifikatfil (förval: server.cert) + Serverns certifikatfil (förvalt: server.cert) - + Server private key (default: server.pem) - Serverns privata nyckel (förval: server.pem) + Serverns privata nyckel (förvalt: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Accepterade krypteringsalgoritmer (förval: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Accepterade krypteringsalgoritmer (förvalt: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - Varning: Hårddiskutrymme börjar bli lågt - - - + This help message Det här hjälp medelandet - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Kan inte låsa data-mappen %s. Bitcoin körs förmodligen redan. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) Det går inte att binda till %s på den här datorn (bind returnerade felmeddelande %d, %s) - + Connect through socks proxy Anslut genom socks-proxy - - Select the version of socks proxy to use (4 or 5, 5 is default) - Välj socks-proxy version att använda (4 eller 5, 5 är standard) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - Använd inte en proxy för anslutningar till nätverket <net> (IPv4 eller IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect Tillåt DNS-sökningar för -addnode, -seednode och -connect - - Pass DNS requests to (SOCKS5) proxy - Skicka vidare DNS-förfrågningar till (SOCKS5) proxy - - - + Loading addresses... Laddar adresser... - - Error loading blkindex.dat - Fel vid inläsning av blkindex.dat - - - + Error loading wallet.dat: Wallet corrupted Fel vid inläsningen av wallet.dat: Plånboken är skadad - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Fel vid inläsningen av wallet.dat: Plånboken kräver en senare version av Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Fel vid inläsningen av wallet.dat: Plånboken kräver en senare version av CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - Plånboken behöver skrivas om: Starta om Bitcoin för att färdigställa + + Wallet needed to be rewritten: restart CasinoCoin to complete + Plånboken behöver skrivas om: Starta om CasinoCoin för att färdigställa - + Error loading wallet.dat Fel vid inläsning av plånboksfilen wallet.dat - + Invalid -proxy address: '%s' Ogiltig -proxy adress: '%s' - - Unknown network specified in -noproxy: '%s' - Okänt nätverk som anges i -noproxy: '%s' - - - + Unknown network specified in -onlynet: '%s' Okänt nätverk som anges i -onlynet: '%s' - + Unknown -socks proxy version requested: %i Okänd -socks proxy version begärd: %i - + Cannot resolve -bind address: '%s' Kan inte matcha -bind adress: '%s' - - Not listening on any port - Lyssnar ej på någon port - - - + Cannot resolve -externalip address: '%s' Kan inte matcha -externalip adress: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ogiltigt belopp för -paytxfee=<belopp>:'%s' - - Error: could not start node - Fel: kunde inte starta nod - - - - Error: Wallet locked, unable to create transaction - Fel: Plånboken är låst, det går ej att skapa en transaktion - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Fel: Denna transaktion kräver en transaktionsavgift på minst %s på grund av dess storlek, komplexitet, eller användning av senast mottagna bitcoins - - - - Error: Transaction creation failed - Fel: Transaktionen gick inte att skapa - - - - Sending... - Skickar... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Fel: Transaktionen avslogs. Detta kan hända om några av mynten i plånboken redan spenderats, t.ex om du använt en kopia av wallet.dat och mynt spenderades i kopian men inte markerats som spenderas här. - - - + Invalid amount Ogiltig mängd - + Insufficient funds - Otillräckligt med bitcoins + Otillräckligt med casinocoins - + Loading block index... Laddar blockindex... - + Add a node to connect to and attempt to keep the connection open Lägg till en nod att koppla upp mot och försök att hålla anslutningen öppen - - Unable to bind to %s on this computer. Bitcoin is probably already running. - Det går inte att binda till %s på den här datorn. Bitcoin är förmodligen redan igång. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Det går inte att binda till %s på den här datorn. CasinoCoin är förmodligen redan igång. - - Find peers using internet relay chat (default: 0) - Sök efter klienter med internet relay chat (standard: 0) - - - - Accept connections from outside (default: 1) - Acceptera anslutningar utifrån (standard: 1) - - - - Find peers using DNS lookup (default: 1) - Sök efter klienter med DNS sökningen (standard: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Använd Universal Plug and Play för att mappa den lyssnande porten (standard: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Använd Universal Plug and Play för att mappa den lyssnande porten (standard: 0) - - - + Fee per KB to add to transactions you send Avgift per KB att lägga till på transaktioner du skickar - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - Varning: -paytxfee är satt väldigt hög. Detta är avgiften du kommer betala för varje transaktion. - - - + Loading wallet... Laddar plånbok... - + Cannot downgrade wallet Kan inte nedgradera plånboken - - Cannot initialize keypool - Kan inte initiera keypool - - - + Cannot write default address Kan inte skriva standardadress - + Rescanning... Söker igen... - + Done loading Klar med laddning - + To use the %s option Att använda %s alternativet - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, du behöver sätta ett rpclösensord i konfigurationsfilen: - %s -Det är rekommenderat att använda följande slumpade lösenord: -rpcuser=bitcoinrpc -rpcpassword=%s -(du behöver inte komma ihåg lösenordet) -Om filen inte existerar, skapa den med enbart ägarläsbara filrättigheter. - - - - + Error Fel - - An error occured while setting up the RPC port %i for listening: %s - Ett fel uppstod vid upprättandet av RPC port %i för att lyssna: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2511,10 +2935,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Om filen inte existerar, skapa den med filrättigheten endast läsbar för ägaren. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Varning: Vänligen kolla så din dators datum och tid är korrekt. Om din klocka går fel kommer Bitcoin inte fungera korrekt. - - \ No newline at end of file + diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts new file mode 100644 index 0000000..ced532d --- /dev/null +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About CasinoCoin + เกี่ยวกับ บิตคอย์น + + + + <b>CasinoCoin</b> version + <b>บิตคอย์น<b>รุ่น + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The CasinoCoin developers + + + + + AddressBookPage + + + Address Book + สมุดรายชื่อ + + + + Double-click to edit address or label + ดับเบิลคลิก เพื่อแก้ไขที่อยู่ หรือชื่อ + + + + Create a new address + สร้างที่อยู่ใหม่ + + + + Copy the currently selected address to the system clipboard + คัดลอกที่อยู่ที่ถูกเลือกไปยัง คลิปบอร์ดของระบบ + + + + &New Address + + + + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a CasinoCoin address + + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + + + + + &Verify Message + + + + + &Delete + ลบ + + + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + + + + + Export Address Book Data + ส่งออกรายชื่อทั้งหมด + + + + Comma separated file (*.csv) + + + + + Error exporting + ส่งออกผิดพลาด + + + + Could not write to file %1. + ไม่สามารถเขียนไปยังไฟล์ %1 + + + + AddressTableModel + + + Label + ชื่อ + + + + Address + ที่อยู่ + + + + (no label) + (ไม่มีชื่อ) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + ใส่รหัสผ่าน + + + + New passphrase + รหัสผา่นใหม่ + + + + Repeat new passphrase + กรุณากรอกรหัสผ่านใหม่อีกครั้งหนึ่ง + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + + + + + Encrypt wallet + กระเป๋าสตางค์ที่เข้ารหัส + + + + This operation needs your wallet passphrase to unlock the wallet. + + + + + Unlock wallet + เปิดกระเป๋าสตางค์ + + + + This operation needs your wallet passphrase to decrypt the wallet. + + + + + Decrypt wallet + ถอดรหัสกระเป๋าสตางค์ + + + + Change passphrase + เปลี่ยนรหัสผ่าน + + + + Enter the old and new passphrase to the wallet. + กรอกรหัสผ่านเก่าและรหัสผ่านใหม่สำหรับกระเป๋าสตางค์ + + + + Confirm wallet encryption + ยืนยันการเข้ารหัสกระเป๋าสตางค์ + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + 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. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + กระเป๋าสตางค์ถูกเข้ารหัสเรียบร้อยแล้ว + + + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + การเข้ารหัสกระเป๋าสตางค์ผิดพลาด + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + + + + The supplied passphrases do not match. + รหัสผ่านที่คุณกรอกไม่ตรงกัน + + + + Wallet unlock failed + + + + + + + The passphrase entered for the wallet decryption was incorrect. + + + + + Wallet decryption failed + + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + + + + + &Overview + + + + + Show general overview of wallet + + + + + &Transactions + + + + + Browse transaction history + + + + + Edit the list of stored addresses and labels + + + + + Show the list of addresses for receiving payments + + + + + E&xit + + + + + Quit application + + + + + Show information about CasinoCoin + + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a CasinoCoin address + + + + + Modify configuration options for CasinoCoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + CasinoCoin + + + + + Wallet + + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About CasinoCoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + + + + + &File + + + + + &Settings + + + + + &Help + + + + + Tabs toolbar + + + + + + [testnet] + + + + + CasinoCoin client + + + + + %n active connection(s) to CasinoCoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + + + + + Warning + + + + + Information + + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid CasinoCoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + CasinoCoin-Qt + + + + + version + + + + + Usage: + + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start CasinoCoin after logging in to the system. + + + + + &Start CasinoCoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting CasinoCoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + CasinoCoin - Debug window + + + + + CasinoCoin Core + + + + + Debug log file + + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the CasinoCoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this CasinoCoin address + + + + + Sign &Message + + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Click "Sign Message" to generate signature + + + + + Enter CasinoCoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + + + + + Source + + + + + Generated + + + + + + From + + + + + + + To + + + + + + own address + + + + + label + + + + + + + + + Credit + + + + + matures in %n more block(s) + + + + + not accepted + + + + + + + + Debit + + + + + Transaction fee + + + + + Net amount + + + + + Message + + + + + Comment + + + + + Transaction ID + + + + + Generated coins must mature 120 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. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + + + + + true + + + + + false + + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + + + + + Type + + + + + Address + ที่อยู่ + + + + Amount + + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + + + + + Received from + + + + + Sent to + + + + + Payment to yourself + + + + + Mined + + + + + (n/a) + + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + + + + + Type of transaction. + + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + + + + + Today + วันนี้ + + + + This week + + + + + This month + + + + + Last month + + + + + This year + + + + + Range... + + + + + Received with + + + + + Sent to + + + + + To yourself + + + + + Mined + + + + + Other + + + + + Enter address or label to search + + + + + Min amount + + + + + Copy address + + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + + + + + Type + + + + + Label + ชื่อ + + + + Address + ที่อยู่ + + + + Amount + + + + + ID + + + + + Error exporting + ส่งออกผิดพลาด + + + + Could not write to file %1. + ไม่สามารถเขียนไปยังไฟล์ %1 + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + CasinoCoin version + + + + + Usage: + + + + + Send command to -server or casinocoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: casinocoin.conf) + + + + + Specify pid file (default: casinocoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 47950 or testnet: 17950) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + + + + + To use the %s option + + + + + Error + + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index 4e0e82d..37f0307 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - Bitcoin hakkında + + About CasinoCoin + CasinoCoin hakkında - - <b>Bitcoin</b> version - <b>Bitcoin</b> sürüm + + <b>CasinoCoin</b> version + <b>CasinoCoin</b> sürüm - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Telif hakkı © 2009-2012 Bitcoin geliştiricileri + + Bu yazılım deneme safhasındadır. -Bu yazılım deneme safhasındadır. + MIT/X11 yazılım lisansı kapsamında yayınlanmıştır, COPYING dosyasına ya da http://www.opensource.org/licenses/mit-license.php sayfasına bakınız. -MIT/X11 yazılım lisansı kapsamında yayınlanmıştır, license.txt dosyasına ya da http://www.opensource.org/licenses/mit-license.php sayfasına bakınız. - -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 yazılmış şifreleme yazılımları ve Thomas Bernard tarafından programlanmış UPnP yazılımı içerir. + 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. + + + + Copyright + Telif hakkı + + + + The CasinoCoin developers + CasinoCoin geliştiricileri AddressBookPage - + Address Book Adres defteri - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Bunlar, ödemeleri almak için Bitcoin adresleridir. Kimin ödeme yaptığını izleyebilmek için her ödeme yollaması gereken kişiye değişik bir adres verebilirsiniz. - - - + Double-click to edit address or label Adresi ya da etiketi düzenlemek için çift tıklayınız - + Create a new address Yeni bir adres oluştur - + Copy the currently selected address to the system clipboard - Şu anda seçili olan adresi panoya kopyalar + Şu anda seçili olan adresi panoya kopyala - + &New Address &Yeni adres - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Bunlar, ödeme almak için CasinoCoin adresleridir. Kimin ödeme yaptığını izleyebilmek için her ödeme yollaması gereken kişiye değişik bir adres verebilirsiniz. + + + &Copy Address Adresi &kopyala - + Show &QR Code &QR kodunu göster - - Sign a message to prove you own this address - Bu adresin sizin olduğunu ispatlamak için mesaj imzalayın + + Sign a message to prove you own a CasinoCoin address + Bir CasinoCoin adresinin sizin olduğunu ispatlamak için mesaj imzalayın - - &Sign Message - Mesaj &imzala + + Sign &Message + &Mesaj imzala - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Seçilen adresi listeden siler. Sadece gönderi adresleri silinebilir. + + Delete the currently selected address from the list + Seçili adresi listeden sil - + + Export the data in the current tab to a file + Güncel sekmedeki verileri bir dosyaya aktar + + + + &Export + &Dışa aktar + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Belirtilen CasinoCoin adresi ile imzalandığını doğrulamak için bir mesajı kontrol et + + + + &Verify Message + Mesaj &kontrol et + + + &Delete &Sil - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Bunlar ödeme yapmak için kullanacağınız CasinoCoin adreslerinizdir. CasinoCoin yollamadan önce meblağı ve alıcı adresini daima kontrol ediniz. + + + Copy &Label &Etiketi kopyala - + &Edit &Düzenle - + + Send &Coins + Bit&coin Gönder + + + Export Address Book Data Adres defteri verilerini dışa aktar - + Comma separated file (*.csv) Virgülle ayrılmış değerler dosyası (*.csv) - + Error exporting Dışa aktarımda hata oluştu - + Could not write to file %1. %1 dosyasına yazılamadı. @@ -126,17 +164,17 @@ Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl AddressTableModel - + Label Etiket - + Address Adres - + (no label) (boş etiket) @@ -144,432 +182,460 @@ Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl AskPassphraseDialog - + Passphrase Dialog Parola diyaloğu - + Enter passphrase Parolayı giriniz - + New passphrase Yeni parola - + Repeat new passphrase Yeni parolayı tekrarlayınız - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. Cüzdanınız için yeni parolayı giriniz.<br/>Lütfen <b>10 ya da daha fazla rastgele karakter</b> veya <b>sekiz ya da daha fazla kelime</b> içeren bir parola seçiniz. - + Encrypt wallet Cüzdanı şifrele - + This operation needs your wallet passphrase to unlock the wallet. Bu işlem cüzdan kilidini açmak için cüzdan parolanızı gerektirir. - + Unlock wallet Cüzdan kilidini aç - + This operation needs your wallet passphrase to decrypt the wallet. Bu işlem, cüzdan şifresini açmak için cüzdan parolasını gerektirir. - + Decrypt wallet Cüzdan şifresini aç - + Change passphrase Parolayı değiştir - + Enter the old and new passphrase to the wallet. Cüzdan için eski ve yeni parolaları giriniz. - + Confirm wallet encryption Cüzdan şifrelenmesini teyit eder - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - UYARI: Eğer cüzdanınızı şifrelerseniz ve parolanızı kaybederseniz, <b>TÜM BİTCOİNLERİNİZİ KAYBEDERSİNİZ</b>! -Cüzdanınızı şifrelemek istediğinizden emin misiniz? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + Uyarı: Eğer cüzdanınızı şifrelerseniz ve parolanızı kaybederseniz, <b>TÜM BİTCOİNLERİNİZİ KAYBEDERSİNİZ</b>! - - + + Are you sure you wish to encrypt your wallet? + Cüzdanınızı şifrelemek istediğinizden emin misiniz? + + + + 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. + Ö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. + + + + + Warning: The Caps Lock key is on! + Uyarı: Caps Lock tuşu faal durumda! + + + + Wallet encrypted Cüzdan şifrelendi - - Bitcoin 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. - Şifreleme işlemini tamamlamak için Bitcoin şimdi kapanacaktır. Cüzdanınızı şifrelemenin, Bitcoinlerinizin bilgisayara bulaşan kötücül bir yazılım tarafından çalınmaya karşı tamamen koruyamayacağını unutmayınız. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + Şifreleme işlemini tamamlamak için CasinoCoin şimdi kapanacaktır. Cüzdanınızı şifrelemenin, CasinoCoinlerinizin bilgisayara bulaşan kötücül bir yazılım tarafından çalınmaya karşı tamamen koruyamayacağını unutmayınız. - - - Warning: The Caps Lock key is on. - Uyarı: Caps Lock tuşu etkin durumda. - - - - - - + + + + Wallet encryption failed Cüzdan şifrelemesi başarısız oldu - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Dahili bir hata sebebiyle cüzdan şifrelemesi başarısız oldu. Cüzdanınız şifrelenmedi. - - + + The supplied passphrases do not match. Girilen parolalar birbirleriyle uyumlu değil. - + Wallet unlock failed Cüzdan kilidinin açılması başarısız oldu - - - + + + The passphrase entered for the wallet decryption was incorrect. Cüzdan şifresinin açılması için girilen parola yanlıştı. - + Wallet decryption failed Cüzdan şifresinin açılması başarısız oldu - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Cüzdan parolası başarılı bir şekilde değiştirildi. BitcoinGUI - - Bitcoin Wallet - Bitcoin cüzdanı - - - + Sign &message... &Mesaj imzala... - - Show/Hide &Bitcoin - &Bitcoin'i Göster/Sakla - - - + Synchronizing with network... Şebeke ile senkronizasyon... - + &Overview &Genel bakış - + Show general overview of wallet - Cüzdana genel bakışı gösterir + Cüzdana genel bakışı göster - + &Transactions &Muameleler - + Browse transaction history Muamele tarihçesini tara - - &Address Book - &Adres defteri - - - + Edit the list of stored addresses and labels - Saklanan adres ve etiket listesini düzenler + Saklanan adres ve etiket listesini düzenle - - &Receive coins - Bitcoin &al - - - + Show the list of addresses for receiving payments - Ödeme alma adreslerinin listesini gösterir + Ödeme alma adreslerinin listesini göster - - &Send coins - Bitcoin &yolla - - - - Prove you control an address - Bu adresin kontrolünüz altında olduğunu ispatlayın - - - + E&xit &Çık - + Quit application - Uygulamadan çıkar + Uygulamadan çık - - &About %1 - %1 &hakkında + + Show information about CasinoCoin + CasinoCoin hakkında bilgi göster - - Show information about Bitcoin - Bitcoin hakkında bilgi gösterir - - - + About &Qt &Qt hakkında - + Show information about Qt - Qt hakkında bilgi görüntüler + Qt hakkında bilgi görüntü - + &Options... &Seçenekler... - + &Encrypt Wallet... Cüzdanı &şifrele... - + &Backup Wallet... Cüzdanı &yedekle... - + &Change Passphrase... Parolayı &değiştir... - - - ~%n block(s) remaining - ~%n blok kaldı + + + Importing blocks from disk... + Bloklar diskten içe aktarılıyor... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - Muamele tarihçesinden %1 blok indirildi (toplam %2 blok, %%3 tamamlandı). + + Reindexing blocks on disk... + Diskteki bloklar yeniden endeksleniyor... - - &Export... - &Dışa aktar... + + Send coins to a CasinoCoin address + Bir CasinoCoin adresine CasinoCoin yolla - - Send coins to a Bitcoin address - Bir Bitcoin adresine Bitcoin yollar + + Modify configuration options for CasinoCoin + CasinoCoin seçeneklerinin yapılandırmasını değiştir - - Modify configuration options for Bitcoin - Bitcoin seçeneklerinin yapılandırmasını değiştirir - - - - Show or hide the Bitcoin window - Bitcoin penceresini göster ya da sakla - - - - Export the data in the current tab to a file - Güncel sekmedeki verileri bir dosyaya aktar - - - - Encrypt or decrypt wallet - Cüzdanı şifreler ya da şifreyi açar - - - + Backup wallet to another location Cüzdanı diğer bir konumda yedekle - + Change the passphrase used for wallet encryption - Cüzdan şifrelemesi için kullanılan parolayı değiştirir + Cüzdan şifrelemesi için kullanılan parolayı değiştir - + &Debug window &Hata ayıklama penceresi - + Open debugging and diagnostic console Hata ayıklama ve teşhis penceresini aç - + &Verify message... - &Mesaj kontrol et... + Mesaj &kontrol et... - - Verify a message signature - Mesaj imzasını kontrol et + + + CasinoCoin + CasinoCoin - + + Wallet + Cüzdan + + + + &Send + &Gönder + + + + &Receive + &Al + + + + &Addresses + &Adresler + + + + &About CasinoCoin + CasinoCoin &Hakkında + + + + &Show / Hide + &Göster / Sakla + + + + Show or hide the main Window + Ana pencereyi görüntüle ya da sakla + + + + Encrypt the private keys that belong to your wallet + Cüzdanınızın özel anahtarlarını şifrele + + + + Sign messages with your CasinoCoin addresses to prove you own them + Mesajları adreslerin size ait olduğunu ispatlamak için CasinoCoin adresleri ile imzala + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Belirtilen CasinoCoin adresleri ile imzalandıklarından emin olmak için mesajları kontrol et + + + &File &Dosya - + &Settings &Ayarlar - + &Help &Yardım - + Tabs toolbar Sekme araç çubuğu - - Actions toolbar - Faaliyet araç çubuğu - - - - + + [testnet] [testnet] - - - Bitcoin client - Bitcoin istemcisi + + CasinoCoin client + CasinoCoin istemcisi - - %n active connection(s) to Bitcoin network - Bitcoin şebekesine %n etkin bağlantı + + %n active connection(s) to CasinoCoin network + CasinoCoin şebekesine %n faal bağlantıCasinoCoin şebekesine %n faal bağlantı - - Downloaded %1 blocks of transaction history. - Muamele tarihçesinin %1 adet bloku indirildi. - - - - %n second(s) ago - %n saniye önce - - - - %n minute(s) ago - %n dakika önce - - - - %n hour(s) ago - %n saat önce - - - - %n day(s) ago - %n gün önce + + No block source available... + Hiçbir blok kaynağı mevcut değil... - + + Processed %1 of %2 (estimated) blocks of transaction history. + Muamele tarihçesinin toplam (tahmini) %2 blokundan %1 blok işlendi. + + + + Processed %1 blocks of transaction history. + Muamele tarihçesinde %1 blok işlendi. + + + + %n hour(s) + %n saat%n saat + + + + %n day(s) + %n gün%n gün + + + + %n week(s) + %n hafta%n hafta + + + + %1 behind + %1 geride + + + + Last received block was generated %1 ago. + Son alınan blok %1 evvel oluşturulmuştu. + + + + Transactions after this will not yet be visible. + Bundan sonraki muameleler henüz görüntülenemez. + + + + Error + Hata + + + + Warning + Uyarı + + + + Information + Bilgi + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Bu muamele boyut sınırlarını aşmıştır. Gene de %1 ücret ödeyerek gönderebilirsiniz, ki bu ücret muamelenizi işleyen ve şebekeye yardım eden düğümlere ödenecektir. Ücreti ödemek istiyor musunuz? + + + Up to date Güncel - + Catching up... Aralık kapatılıyor... - - Last received block was generated %1. - Son alınan blok şu vakit oluşturulmuştu: %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Bu muamele boyut sınırlarını aşmıştır. Gene de %1 ücret ödeyerek gönderebilirsiniz, ki bu ücret muamelenizi işleyen ve şebekeye yardım eden düğümlere ödenecektir. Ücreti ödemek istiyor musunuz? - - - + Confirm transaction fee Muamele ücretini teyit et - + Sent transaction Muamele yollandı - + Incoming transaction Gelen muamele - + Date: %1 Amount: %2 Type: %3 @@ -582,538 +648,485 @@ Adres: %4 - - Wallet is <b>encrypted</b> and currently <b>unlocked</b> - Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilidi açılmıştır</b> + + + URI handling + URI yönetimi - + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI okunamadı! Sebebi geçersiz bir CasinoCoin adresi veya hatalı URI parametreleri olabilir. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilidi açıktır</b> + + + Wallet is <b>encrypted</b> and currently <b>locked</b> Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilitlidir</b> - - Backup Wallet - Cüzdanı yedekle - - - - Wallet Data (*.dat) - Cüzdan verileri (*.dat) - - - - Backup Failed - Yedekleme başarısız oldu - - - - There was an error trying to save the wallet data to the new location. - Cüzdan verilerinin başka bir konumda kaydedilmesi sırasında bir hata meydana geldi. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - Ciddi bir hata oluştu. Artık Bitcoin güvenli bir şekilde işlemeye devam edemez ve kapanacaktır. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + Ciddi bir hata oluştu. CasinoCoin artık güvenli bir şekilde işlemeye devam edemez ve kapanacaktır. ClientModel - + Network Alert Şebeke hakkında uyarı - - DisplayOptionsPage - - - Display - Görünüm - - - - default - varsayılan - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - Kullanıcı arayüzünün dili burada belirtilebilir. Bu ayar Bitcoin tekrar başlatıldığında etkinleşecektir. - - - - User Interface &Language: - Kullanıcı arayüzü &lisanı: - - - - &Unit to show amounts in: - Miktarı göstermek için &birim: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Bitcoin gönderildiğinde arayüzde gösterilecek varsayılan alt birimi seçiniz - - - - &Display addresses in transaction list - Muamele listesinde adresleri &göster - - - - Whether to show Bitcoin addresses in the transaction list - Muamele listesinde Bitcoin adreslerinin gösterilip gösterilmeyeceklerini belirler - - - - Warning - Uyarı - - - - This setting will take effect after restarting Bitcoin. - Bu ayarlar Bitcoin tekrar başlatıldığında etkinleşecektir. - - EditAddressDialog - + Edit Address Adresi düzenle - + &Label &Etiket - + The label associated with this address book entry Bu adres defteri unsuru ile ilişkili etiket - + &Address &Adres - + The address associated with this address book entry. This can only be modified for sending addresses. Bu adres defteri unsuru ile ilişkili adres. Bu, sadece gönderi adresi için değiştirilebilir. - + New receiving address Yeni alım adresi - + New sending address Yeni gönderi adresi - + Edit receiving address Alım adresini düzenle - + Edit sending address Gönderi adresini düzenle - + The entered address "%1" is already in the address book. Girilen "%1" adresi hâlihazırda adres defterinde mevcuttur. - - The entered address "%1" is not a valid Bitcoin address. - Girilen "%1" adresi geçerli bir Bitcoin adresi değildir. + + The entered address "%1" is not a valid CasinoCoin address. + Girilen "%1" adresi geçerli bir CasinoCoin adresi değildir. - + Could not unlock wallet. Cüzdan kilidi açılamadı. - + New key generation failed. Yeni anahtar oluşturulması başarısız oldu. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version sürüm - + Usage: Kullanım: - - options - seçenekler + + command-line options + komut satırı seçenekleri - + UI options Kullanıcı arayüzü seçenekleri - + Set language, for example "de_DE" (default: system locale) Lisan belirt, mesela "de_De" (varsayılan: sistem dili) - + Start minimized - Küçültülmüş olarak başla + Küçültülmüş olarak başlat - + Show splash screen on startup (default: 1) Başlatıldığında başlangıç ekranını göster (varsayılan: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - Çıkışta blok ve adres veri tabanlarını ayırır. Bu, kapanışı yavaşlatır ancak veri tabanlarının başka klasörlere taşınabilmelerine imkân sağlar. Cüzdan daima ayırılır. + + Options + Seçenekler - + + &Main + &Esas ayarlar + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Muamelelerin hızlı işlenmesini garantilemeye yardım eden, seçime dayalı kB başı muamele ücreti. Muamelelerin çoğunluğunun boyutu 1 kB'dir. + + + Pay transaction &fee Muamele ücreti &öde - - Main - Ana menü + + Automatically start CasinoCoin after logging in to the system. + Sistemde oturum açıldığında CasinoCoin'i otomatik olarak başlat. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Muamelelerin hızlı işlenmesini garantilemeye yardım eden, seçime dayalı kB başı muamele ücreti. Muamelelerin çoğunluğunun boyutu 1 kB'dir. 0.01 ücreti önerilir. + + &Start CasinoCoin on system login + CasinoCoin'i sistem oturumuyla &başlat - - &Start Bitcoin on system login - Bitcoin'i sistem oturumuyla &başlat + + Reset all client options to default. + İstemcinin tüm seçeneklerini varsayılan değerlere geri al. - - Automatically start Bitcoin after logging in to the system - Sistemde oturum açıldığında Bitcoin'i otomatik olarak başlat + + &Reset Options + Seçenekleri &sıfırla - - &Detach databases at shutdown - Kapanışta veritabanlarını &ayır - - - - MessagePage - - - Sign Message - Mesaj imzala + + &Network + &Şebeke - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - Bir adresin sizin olduğunu ispatlamak için adresinizle mesaj imzalayabilirsiniz. Oltalama saldırılarının kimliğinizi imzanızla elde etmeyi deneyebilecekleri için belirsiz hiçbir şey imzalamamaya dikkat ediniz. Sadece ayrıntılı açıklaması olan ve tümüne katıldığınız ifadeleri imzalayın. + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Yönlendiricide CasinoCoin istemci portlarını otomatik olarak açar. Bu, sadece yönlendiricinizin UPnP desteği bulunuyorsa ve etkinse çalışabilir. - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Mesajı imzalamak için kullanılacak adres (mesela 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - Adres defterinden adres seç - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Panodan adres yapıştır - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - İmzalamak istediğiniz mesajı burada giriniz - - - - Copy the current signature to the system clipboard - Güncel imzayı sistem panosuna kopyala - - - - &Copy Signature - İmzayı &kopyala - - - - Reset all sign message fields - Tüm mesaj alanlarını sıfırla - - - - Clear &All - Tümünü &temizle - - - - Click "Sign Message" to get signature - İmza elde etmek için "Mesaj İmzala" unsurunu tıklayın - - - - Sign a message to prove you own this address - Bu adresin sizin olduğunu ispatlamak için bir mesaj imzalayın - - - - &Sign Message - Mesaj &İmzala - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Bitcoin adresi giriniz (mesela 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - İmza sırasında hata meydana geldi - - - - %1 is not a valid address. - %1 geçerli bir adres değildir. - - - - %1 does not refer to a key. - %1 herhangi bir anahtara işaret etmemektedir. - - - - Private key for %1 is not available. - %1 için özel anahtar mevcut değil. - - - - Sign failed - İmzalama başarısız oldu - - - - NetworkOptionsPage - - - Network - Şebeke - - - + Map port using &UPnP Portları &UPnP kullanarak haritala - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Yönlendiricide Bitcoin istemci portlarını otomatik olarak açar. Bu, sadece yönlendiricinizin UPnP desteği bulunuyorsa ve etkinse çalışabilir. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + CasinoCoin şebekesine SOCKS vekil sunucusu vasıtasıyla bağlan (mesela Tor ile bağlanıldığında). - - &Connect through SOCKS4 proxy: - SOCKS4 vekil sunucusu vasıtasıyla ba&ğlan: + + &Connect through SOCKS proxy: + SOCKS vekil sunucusu vasıtasıyla ba&ğlan: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Bitcoin şebekesine SOCKS4 vekil sunucusu vasıtasıyla bağlanır (mesela Tor ile bağlanıldığında) - - - + Proxy &IP: Vekil &İP: - - &Port: - &Port: - - - + IP address of the proxy (e.g. 127.0.0.1) Vekil sunucunun İP adresi (mesela 127.0.0.1) - - Port of the proxy (e.g. 1234) - Vekil sunucun portu (örneğin 1234) + + &Port: + &Port: - - - OptionsDialog - - Options - Seçenekler + + Port of the proxy (e.g. 9050) + Vekil sunucunun portu (mesela 9050) + + + + SOCKS &Version: + SOCKS &sürümü: + + + + SOCKS version of the proxy (e.g. 5) + Vekil sunucunun SOCKS sürümü (mesela 5) + + + + &Window + &Pencere + + + + Show only a tray icon after minimizing the window. + Küçültüldükten sonra sadece çekmece ikonu göster. + + + + &Minimize to the tray instead of the taskbar + İşlem çubuğu yerine sistem çekmecesine &küçült + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Pencere kapatıldığında uygulamadan çıkmak yerine uygulamayı küçültür. Bu seçenek etkinleştirildiğinde, uygulama sadece menüden çıkış seçildiğinde kapanacaktır. + + + + M&inimize on close + Kapatma sırasında k&üçült + + + + &Display + &Görünüm + + + + User Interface &language: + Kullanıcı arayüzü &lisanı: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Kullanıcı arayüzünün dili burada belirtilebilir. Bu ayar CasinoCoin tekrar başlatıldığında etkinleşecektir. + + + + &Unit to show amounts in: + Miktarı göstermek için &birim: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + CasinoCoin gönderildiğinde arayüzde gösterilecek varsayılan alt birimi seçiniz. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + Muamele listesinde CasinoCoin adreslerinin gösterilip gösterilmeyeceklerini belirler. + + + + &Display addresses in transaction list + Muamele listesinde adresleri &göster + + + + &OK + &Tamam + + + + &Cancel + &İptal + + + + &Apply + &Uygula + + + + default + varsayılan + + + + Confirm options reset + Seçeneklerin sıfırlanmasını teyit et + + + + Some settings may require a client restart to take effect. + Bazı ayarların dikkate alınması istemcinin tekrar başlatılmasını gerektirebilir. + + + + Do you want to proceed? + Devam etmek istiyor musunuz? + + + + + Warning + Uyarı + + + + + This setting will take effect after restarting CasinoCoin. + Bu ayarlar CasinoCoin tekrar başlatıldığında etkinleşecektir. + + + + The supplied proxy address is invalid. + Girilen vekil sunucu adresi geçersizdir. OverviewPage - + Form Form - - - 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. - Görüntülenen veriler zaman aşımını 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. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + 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. - + Balance: Bakiye: - - Number of transactions: - Muamele sayısı: - - - + Unconfirmed: Doğrulanmamış: - + Wallet Cüzdan - + + Immature: + Olgunlaşmamış: + + + + Mined balance that has not yet matured + Oluşturulan bakiye henüz olgunlaşmamıştır + + + <b>Recent transactions</b> <b>Son muameleler</b> - + Your current balance Güncel bakiyeniz - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance Doğrulanması beklenen ve henüz güncel bakiyeye ilâve edilmemiş muamelelerin toplamı - - Total number of transactions in wallet - Cüzdandaki muamelelerin toplam sayısı - - - - + + out of sync eşleşme dışı + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + CasinoCoin başlatılamadı: tıkla-ve-öde yöneticisi + + QRCodeDialog - + QR Code Dialog QR kodu diyaloğu - - QR Code - QR Kodu - - - + Request Payment - Ödeme isteği + Ödeme talebi - + Amount: Miktar: - - BTC - BTC - - - + Label: Etiket: - + Message: Mesaj: - + &Save As... &Farklı kaydet... - + Error encoding URI into QR Code. URI'nin QR koduna kodlanmasında hata oluştu. - + + The entered amount is invalid, please check. + Girilen miktar geçersizdir, kontrol ediniz. + + + Resulting URI too long, try to reduce the text for label / message. Sonuç URI çok uzun, etiket ya da mesaj metnini kısaltmayı deneyiniz. - + Save QR Code QR kodu kaydet - + PNG Images (*.png) PNG resimleri (*.png) @@ -1121,125 +1134,146 @@ Adres: %4 RPCConsole - - Bitcoin debug window - Bitcoin hata ayıklama penceresi - - - + Client name İstemci ismi - - - - - - - - - + + + + + + + + + + N/A Mevcut değil - + Client version İstemci sürümü - + &Information &Malumat - - Client - İstemci + + Using OpenSSL version + Kullanılan OpenSSL sürümü - + Startup time Başlama zamanı - + Network Şebeke - + Number of connections Bağlantı sayısı - + On testnet Testnet üzerinde - + Block chain Blok zinciri - + Current number of blocks Güncel blok sayısı - + Estimated total blocks Tahmini toplam blok sayısı - + Last block time Son blok zamanı - - Debug logfile - Hata ayıklama kütük dosyası - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - Güncel veri klasöründen Bitcoin hata ayıklama kütüğünü aç. Büyük kütük dosyaları için bu birkaç saniye alabilir. - - - + &Open &Aç - + + Command-line options + Komut satırı seçenekleri + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Mevcut CasinoCoin komut satırı seçeneklerinin listesini içeren CasinoCoin-Qt yardımını göster. + + + + &Show + &Göster + + + &Console &Konsol - + Build date Derleme tarihi - + + CasinoCoin - Debug window + CasinoCoin - Hata ayıklama penceresi + + + + CasinoCoin Core + CasinoCoin Çekirdeği + + + + Debug log file + Hata ayıklama kütük dosyası + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + Güncel veri klasöründen CasinoCoin hata ayıklama kütük dosyasını açar. Büyük kütük dosyaları için bu birkaç saniye alabilir. + + + Clear console Konsolu temizle - - Welcome to the Bitcoin RPC console. - Bitcoin RPC konsoluna hoş geldiniz. + + Welcome to the CasinoCoin RPC console. + CasinoCoin RPC konsoluna hoş geldiniz. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Tarihçede gezinmek için imleç tuşlarını kullanınız, <b>Ctrl-L</b> ile de ekranı temizleyebilirsiniz. - + Type <b>help</b> for an overview of available commands. Mevcut komutların listesi için <b>help</b> yazınız. @@ -1247,327 +1281,566 @@ Adres: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins - Bitcoin yolla + CasinoCoin yolla - + Send to multiple recipients at once Birçok alıcıya aynı anda gönder - - &Add Recipient - Alıcı &ekle + + Add &Recipient + &Alıcı ekle - + Remove all transaction fields Bütün muamele alanlarını kaldır - + Clear &All Tümünü &temizle - + Balance: Bakiye: - + 123.456 BTC 123.456 BTC - + Confirm the send action Yollama etkinliğini teyit ediniz - - &Send - &Gönder + + S&end + G&önder - + <b>%1</b> to %2 (%3) <b>%1</b> şu adrese: %2 (%3) - + Confirm send coins Gönderiyi teyit ediniz - + Are you sure you want to send %1? %1 göndermek istediğinizden emin misiniz? - + and ve - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. Alıcı adresi geçerli değildir, lütfen denetleyiniz. - + The amount to pay must be larger than 0. Ödeyeceğiniz tutarın sıfırdan yüksek olması gerekir. - + The amount exceeds your balance. Tutar bakiyenizden yüksektir. - + The total exceeds your balance when the %1 transaction fee is included. Toplam, %1 muamele ücreti ilâve edildiğinde bakiyenizi geçmektedir. - + Duplicate address found, can only send to each address once per send operation. Çift adres bulundu, belli bir gönderi sırasında her adrese sadece tek bir gönderide bulunulabilir. - - Error: Transaction creation failed. - Hata: Muamele oluşturması başarısız oldu. + + Error: Transaction creation failed! + Hata: Muamele oluşturması başarısız oldu! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Hata: Muamele reddedildi. Cüzdanınızdaki madenî paraların bazıları zaten harcanmış olduğunda bu meydana gelebilir. Örneğin wallet.dat dosyasının bir kopyasını kullandıysanız ve kopyada para harcandığında ancak burada harcandığı işaretlenmediğinde. + Hata: Muamele reddedildi. Cüzdanınızdaki madenî paraların bazıları zaten harcanmış olduğunda bu meydana gelebilir. Örneğin wallet.dat dosyasının bir kopyasını kullandıysanız ve kopyada para harcandığında ancak burada harcandığı işaretlenmediğinde. SendCoinsEntry - + Form Form - + A&mount: M&iktar: - + Pay &To: &Şu kişiye öde: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Ödemenin gönderileceği adres (mesela Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book Adres defterinize eklemek için bu adrese ilişik bir etiket giriniz - + &Label: &Etiket: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Ödemenin gönderileceği adres (mesela 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Adres defterinden adres seç - + Alt+A Alt+A - + Paste address from clipboard Panodan adres yapıştır - + Alt+P Alt+P - + Remove this recipient Bu alıcıyı kaldır - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Bitcoin adresi giriniz (mesela 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin adresi giriniz (mesela Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + İmzalar - Mesaj İmzala / Kontrol et + + + + &Sign Message + Mesaj &imzala + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Bir adresin sizin olduğunu ispatlamak için adresinizle mesaj imzalayabilirsiniz. Oltalama saldırılarının kimliğinizi imzanızla elde etmeyi deneyebilecekleri için belirsiz 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. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Mesajın imzalanmasında kullanılacak adres (mesela Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Adres defterinden bir adres seç + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Panodan adres yapıştır + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + İmzalamak istediğiniz mesajı burada giriniz + + + + Signature + İmza + + + + Copy the current signature to the system clipboard + Güncel imzayı sistem panosuna kopyala + + + + Sign the message to prove you own this CasinoCoin address + Bu CasinoCoin adresinin sizin olduğunu ispatlamak için mesajı imzalayın + + + + Sign &Message + &Mesajı imzala + + + + Reset all sign message fields + Tüm mesaj alanlarını sıfırla + + + + + Clear &All + Tümünü &temizle + + + + &Verify Message + Mesaj &kontrol et + + + + Enter the signing 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. + İmza için kullanılan adresi, 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. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Mesajı imzalamak için kullanılmış olan adres (mesela Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Belirtilen CasinoCoin adresi ile imzalandığını doğrulamak için mesajı kontrol et + + + + Verify &Message + &Mesaj kontrol et + + + + Reset all verify message fields + Tüm mesaj kontrolü alanlarını sıfırla + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + CasinoCoin adresi giriniz (mesela Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + İmzayı oluşturmak için "Mesaj İmzala" unsurunu tıklayın + + + + Enter CasinoCoin signature + CasinoCoin imzası gir + + + + + The entered address is invalid. + Girilen adres geçersizdir. + + + + + + + Please check the address and try again. + Adresi kontrol edip tekrar deneyiniz. + + + + + The entered address does not refer to a key. + Girilen adres herhangi bir anahtara işaret etmemektedir. + + + + Wallet unlock was cancelled. + Cüzdan kilidinin açılması iptal edildi. + + + + Private key for the entered address is not available. + Girilen adres için özel anahtar mevcut değildir. + + + + Message signing failed. + Mesajın imzalanması başarısız oldu. + + + + Message signed. + Mesaj imzalandı. + + + + The signature could not be decoded. + İmzanın kodu çözülemedi. + + + + + Please check the signature and try again. + İmzayı kontrol edip tekrar deneyiniz. + + + + The signature did not match the message digest. + İmza mesajın hash değeri ile eşleşmedi. + + + + Message verification failed. + Mesaj doğrulaması başarısız oldu. + + + + Message verified. + Mesaj doğrulandı. + + + + SplashScreen + + + The CasinoCoin developers + CasinoCoin geliştiricileri + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - %1 blok için açık - - - + Open until %1 %1 değerine dek açık - - %1/offline? - %1/çevrimdışı mı? + + %1/offline + %1/çevrim dışı - + %1/unconfirmed %1/doğrulanmadı - + %1 confirmations %1 teyit - - <b>Status:</b> - <b>Durum:</b> + + Status + Durum + + + + , broadcast through %n node(s) + , %n düğüm vasıtasıyla yayınlandı, %n düğüm vasıtasıyla yayınlandı - + + Date + Tarih + + + + Source + Kaynak + + + + Generated + Oluşturuldu + + + + + From + Gönderen + + + + + + To + Alıcı + + + + + own address + kendi adresiniz + + + + label + etiket + + + + + + + + Credit + Gider + + + + matures in %n more block(s) + %n ek blok sonrasında olgunlaşacak%n ek blok sonrasında olgunlaşacak + + + + not accepted + kabul edilmedi + + + + + + + Debit + Gelir + + + + Transaction fee + Muamele ücreti + + + + Net amount + Net miktar + + + + Message + Mesaj + + + + Comment + Yorum + + + + Transaction ID + Muamele tanımlayıcı + + + + Generated coins must mature 120 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. + Oluşturulan CasinoCoin'lerin harcanabilmelerinden önce 120 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. + + + + Debug information + Hata ayıklama verileri + + + + Transaction + Muamele + + + + Inputs + Girdiler + + + + Amount + Miktar + + + + true + doğru + + + + false + yanlış + + + , has not been successfully broadcast yet , henüz başarılı bir şekilde yayınlanmadı - - - , broadcast through %1 node - , %1 düğüm vasıtasıyla yayınlandı + + + Open for %n more block(s) + %n ilâve blok için açık%n ilâve blok için açık - - , broadcast through %1 nodes - , %1 düğüm vasıtasıyla yayınlandı - - - - <b>Date:</b> - <b>Tarih:</b> - - - - <b>Source:</b> Generated<br> - <b>Kaynak:</b> Oluşturuldu<br> - - - - - <b>From:</b> - <b>Gönderen:</b> - - - + unknown bilinmiyor - - - - - <b>To:</b> - <b>Alıcı:</b> - - - - (yours, label: - (sizin, etiket: - - - - (yours) - (sizin) - - - - - - - <b>Credit:</b> - <b>Gelir:</b> - - - - (%1 matures in %2 more blocks) - (%1, %2 ek blok sonrasında olgunlaşacak) - - - - (not accepted) - (kabul edilmedi) - - - - - - <b>Debit:</b> - <b>Gider:</b> - - - - <b>Transaction fee:</b> - <b>Muamele ücreti:<b> - - - - <b>Net amount:</b> - <b>Net miktar:</b> - - - - Message: - Mesaj: - - - - Comment: - Yorum: - - - - Transaction ID: - Muamele kimliği: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Oluşturulan Bitcoin'lerin harcanabilmelerinden önce 120 blok beklemeleri gerekmektedir. Bu blok, oluşturduğunuzda, blok zincirine eklenmesi için ağda yayınlandı. Zincire eklenmesi başarısız olursa, "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. - TransactionDescDialog - + Transaction details Muamele detayları - + This pane shows a detailed description of the transaction Bu pano muamelenin ayrıntılı açıklamasını gösterir @@ -1575,117 +1848,117 @@ Adres: %4 TransactionTableModel - + Date Tarih - + Type Tür - + Address Adres - + Amount Miktar - - Open for %n block(s) - %n blok için açık + + Open for %n more block(s) + %n ilâve blok için açık%n ilâve blok için açık - + Open until %1 %1 değerine dek açık - + Offline (%1 confirmations) Çevrimdışı (%1 teyit) - + Unconfirmed (%1 of %2 confirmations) Doğrulanmadı (%1 (toplam %2 üzerinden) teyit) - + Confirmed (%1 confirmations) Doğrulandı (%1 teyit) - - Mined balance will be available in %n more blocks - Madenden çıkarılan bakiye %n ek blok sonrasında kullanılabilecektir + + Mined balance will be available when it matures in %n more block(s) + Madenden çıkarılan bakiye %n ek blok sonrasında olgunlaştığında kullanılabilecektirMadenden çıkarılan bakiye %n ek blok sonrasında olgunlaştığında kullanılabilecektir - + This block was not received by any other nodes and will probably not be accepted! Bu blok başka hiçbir düğüm tarafından alınmamıştır ve muhtemelen kabul edilmeyecektir! - + Generated but not accepted Oluşturuldu ama kabul edilmedi - + Received with Şununla alındı - + Received from Alındığı kişi - + Sent to Gönderildiği adres - + Payment to yourself Kendinize ödeme - + Mined Madenden çıkarılan - + (n/a) (mevcut değil) - + Transaction status. Hover over this field to show number of confirmations. Muamele durumu. Doğrulama sayısını görüntülemek için imleci bu alanda tutunuz. - + Date and time that the transaction was received. Muamelenin alındığı tarih ve zaman. - + Type of transaction. Muamele türü. - + Destination address of transaction. Muamelenin alıcı adresi. - + Amount removed from or added to balance. Bakiyeden alınan ya da bakiyeye eklenen miktar. @@ -1693,817 +1966,967 @@ Adres: %4 TransactionView - - + + All Hepsi - + Today Bugün - + This week Bu hafta - + This month Bu ay - + Last month Geçen ay - + This year Bu sene - + Range... Aralık... - + Received with Şununla alınan - + Sent to Gönderildiği adres - + To yourself Kendinize - + Mined Oluşturulan - + Other Diğer - + Enter address or label to search Aranacak adres ya da etiket giriniz - + Min amount Asgari miktar - + Copy address Adresi kopyala - + Copy label Etiketi kopyala - + Copy amount Miktarı kopyala - + + Copy transaction ID + Muamele kimliğini kopyala + + + Edit label Etiketi düzenle - + Show transaction details Muamele detaylarını göster - + Export Transaction Data Muamele verilerini dışa aktar - + Comma separated file (*.csv) Virgülle ayrılmış değerler dosyası (*.csv) - + Confirmed Doğrulandı - + Date Tarih - + Type Tür - + Label Etiket - + Address Adres - + Amount Miktar - + ID - Kimlik + Tanımlayıcı - + Error exporting Dışa aktarımda hata oluştu - + Could not write to file %1. %1 dosyasına yazılamadı. - + Range: Aralık: - + to ilâ - - VerifyMessageDialog - - - Verify Signed Message - İmzalı mesajı kontrol et - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - Mesajı imzalamak için kullanılan Bitcoin adresini elde etmek için mesaj ve imzayı aşağıda giriniz (yani satırlar, boşluklar ve sekmeler gibi görünmeyen karakterleri doğru şekilde kopyalamaya dikkat ediniz). - - - - Verify a message and obtain the Bitcoin address used to sign the message - Mesajı kontrol et ve imzalamak için kullanılan Bitcoin adresini elde et - - - - &Verify Message - Mesajı &kontrol et - - - - Copy the currently selected address to the system clipboard - Şu anda seçili olan adresi panoya kopyalar - - - - &Copy Address - Adresi &kopyala - - - - Reset all verify message fields - Tüm mesaj kontrolü alanlarını sıfırla - - - - Clear &All - Tümünü &temizle - - - - Enter Bitcoin signature - Bitcoin imzası gir - - - - Click "Verify Message" to obtain address - Adresi elde etmek için "Mesajı kontrol et" düğmesini tıkayınız - - - - - Invalid Signature - Geçersiz imza - - - - The signature could not be decoded. Please check the signature and try again. - İmzanın kodu çözülemedi. İmzayı kontrol edip tekrar deneyiniz. - - - - The signature did not match the message digest. Please check the signature and try again. - İmza mesajın hash değeri eşleşmedi. İmzayı kontrol edip tekrar deneyiniz. - - - - Address not found in address book. - Bu adres, adres defterinde bulunamadı. - - - - Address found in address book: %1 - Adres defterinde bu adres bulundu: %1 - - WalletModel - - Sending... - Gönderiliyor... + + Send Coins + CasinoCoin yolla - WindowOptionsPage + WalletView - - Window - Pencere + + &Export + &Dışa aktar - - &Minimize to the tray instead of the taskbar - İşlem çubuğu yerine sistem çekmecesine &küçült + + Export the data in the current tab to a file + Güncel sekmedeki verileri bir dosyaya aktar - - Show only a tray icon after minimizing the window - Küçültüldükten sonra sadece çekmece ikonu gösterir + + Backup Wallet + Cüzdanı yedekle - - M&inimize on close - Kapatma sırasında k&üçült + + Wallet Data (*.dat) + Cüzdan verileri (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Pencere kapatıldığında uygulamadan çıkmak yerine uygulamayı küçültür. Bu seçenek etkinleştirildiğinde, uygulama sadece menüden çıkış seçildiğinde kapanacaktır. + + Backup Failed + Yedekleme başarısız oldu + + + + There was an error trying to save the wallet data to the new location. + Cüzdanı değişik bir konuma kaydetmek denenirken bir hata meydana geldi. + + + + Backup Successful + Yedekleme başarılı + + + + The wallet data was successfully saved to the new location. + Cüzdan verileri başarılı bir şekilde yeni konuma kaydedildi. bitcoin-core - - Bitcoin version - Bitcoin sürümü + + CasinoCoin version + CasinoCoin sürümü - + Usage: Kullanım: - - Send command to -server or bitcoind - -server ya da bitcoind'ye komut gönder + + Send command to -server or casinocoind + -server ya da casinocoind'ye komut gönder - + List commands Komutları listele - + Get help for a command Bir komut için yardım al - + Options: Seçenekler: - - Specify configuration file (default: bitcoin.conf) - Yapılandırma dosyası belirt (varsayılan: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + Yapılandırma dosyası belirt (varsayılan: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Pid dosyası belirt (varsayılan: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + Pid dosyası belirt (varsayılan: casinocoind.pid) - - Generate coins - Madenî para (Bitcoin) oluştur - - - - Don't generate coins - Bitcoin oluşturmasını devre dışı bırak - - - + Specify data directory Veri dizinini belirt - + Set database cache size in megabytes (default: 25) Veritabanı önbellek boyutunu megabayt olarak belirt (varsayılan: 25) - - Set database disk log size in megabytes (default: 100) - Diskteki veritabanı kütüğü boyutunu megabayt olarak belirt (varsayılan: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Bağlantılar için dinlenecek <port> (varsayılan: 47950 ya da testnet: 17950) - - Specify connection timeout (in milliseconds) - Bağlantı zaman aşım süresini milisaniye olarak belirt - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Bağlantılar için dinlenecek <port> (varsayılan: 8333 ya da testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) Eşler ile en çok <n> adet bağlantı kur (varsayılan: 125) - - Connect only to the specified node - Sadece belirtilen düğüme bağlan - - - + Connect to a node to retrieve peer addresses, and disconnect Eş adresleri elde etmek için bir düğüme bağlan ve ardından bağlantıyı kes - + Specify your own public address Kendi genel adresinizi tanımlayın - - Only connect to nodes in network <net> (IPv4 or IPv6) - Sadece <net> şebekesindeki düğümlere bağlan (IPv4 ya da IPv6) - - - - Try to discover public IP address (default: 1) - Genel IP adresini keşfetmeye çalış (varsayılan: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - Belirtilen adresle ilişiklendir. IPv6 için [makine]:port simgelemini kullanınız - - - + Threshold for disconnecting misbehaving peers (default: 100) Aksaklık gösteren eşlerle bağlantıyı kesme sınırı (varsayılan: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Aksaklık gösteren eşlerle yeni bağlantıları engelleme süresi, saniye olarak (varsayılan: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Her bağlantı için alım tamponu, <n>*1000 bayt (varsayılan: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + IPv4 üzerinde dinlemek için %u numaralı RPC portunun kurulumu sırasında hata meydana geldi: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Her bağlantı için yollama tamponu, <n>*1000 bayt (varsayılan: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + JSON-RPC bağlantılarını <port> üzerinde dinle (varsayılan: 47970 veya tesnet: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - Blok ve adres veri tabanlarını ayır. Kapatma süresini arttırır (varsayılan: 0) - - - + Accept command line and JSON-RPC commands Konut satırı ve JSON-RPC komutlarını kabul et - + Run in the background as a daemon and accept commands Arka planda daemon (servis) olarak çalış ve komutları kabul et - + Use the test network Deneme şebekesini kullan - - Output extra debugging information - İlâve hata ayıklama verisi çıkar + + Accept connections from outside (default: 1 if no -proxy or -connect) + Dışarıdan gelen bağlantıları kabul et (varsayılan: -proxy veya -connect yoksa 1) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, şu yapılandırma dosyasında rpc parolası belirtmeniz gerekir: +%s +Aşağıdaki rastgele oluşturulan parolayı kullanmanız tavsiye edilir: +rpcuser=casinocoinrpc +rpcpassword=%s +(bu parolayı hatırlamanız gerekli değildir) +Kullanıcı ismi ile parolanın FARKLI olmaları gerekir. +Dosya mevcut değilse, sadece sahibi için okumayla sınırlı izin ile oluşturunuz. +Sorunlar hakkında bildiri almak için alertnotify unsurunu ayarlamanız tavsiye edilir; +mesela: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + IPv6 üzerinde dinlemek için %u numaralı RPC portu kurulurken bir hata meydana geldi, IPv4'e dönülüyor: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Belirtilen adrese bağlan ve daima ondan dinle. IPv6 için [makine]:port yazımını kullanınız + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + %s veri dizininde kilit elde edilemedi. CasinoCoin muhtemelen hâlihazırda çalışmaktadır. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Hata: Muamele reddedildi! Cüzdanınızdaki madenî paraların bazıları zaten harcanmış olduğunda bu meydana gelebilir. Örneğin wallet.dat dosyasının bir kopyasını kullandıysanız ve kopyada para harcandığında ancak burada harcandığı işaretlenmediğinde. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Hata: Muamelenin miktarı, karmaşıklığı ya da yakın geçmişte alınan fonların kullanılması nedeniyle bu muamele en az %s tutarında ücret gerektirmektedir! + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + İlgili bir uyarı alındığında komut çalıştır (komuttaki %s mesaj ile değiştirilecektir) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Bir cüzdan muamelesi değiştiğinde komutu çalıştır (komuttaki %s TxID ile değiştirilecektir) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Yüksek öncelikli/düşük ücretli muamelelerin boyutunu bayt olarak tanımla (varsayılan: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Bu yayın öncesi bir deneme sürümüdür - tüm riski siz üstlenmiş olursunuz - casinocoin oluşturmak ya da ticari uygulamalar için kullanmayınız + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Uyarı: -paytxfee çok yüksek bir değere ayarlanmış! Bu, muamele gönderirseniz ödeyeceğiniz muamele ücretidir. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Uyarı: Görüntülenen muameleler doğru olmayabilir! Sizin ya da diğer düğümlerin güncelleme yapması gerekebilir. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Uyarı: Lütfen bilgisayarınızın tarih ve saatinin doğru olup olmadığını kontrol ediniz! Saatiniz doğru değilse CasinoCoin gerektiği gibi çalışamaz. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Uyarı: wallet.dat 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. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Uyarı: wallet.dat bozuk, veriler geri kazanıldı! Özgün wallet.dat, wallet.{zamandamgası}.bak olarak %s klasörüne kaydedildi; bakiyeniz ya da muameleleriniz yanlışsa bir yedeklemeden tekrar yüklemeniz gerekir. + + + + Attempt to recover private keys from a corrupt wallet.dat + Bozuk bir wallet.dat dosyasından özel anahtarları geri kazanmayı dene + + + + Block creation options: + Blok oluşturma seçenekleri: + + + + Connect only to the specified node(s) + Sadece belirtilen düğüme veya düğümlere bağlan + + + + Corrupted block database detected + Bozuk blok veritabanı tespit edildi + + + + Discover own IP address (default: 1 when listening and no -externalip) + Kendi IP adresini keşfet (varsayılan: dinlenildiğinde ve -externalip yoksa 1) + + + + Do you want to rebuild the block database now? + Blok veritabanını şimdi yeniden inşa etmek istiyor musunuz? + + + + Error initializing block database + Blok veritabanını başlatılırken bir hata meydana geldi + + + + Error initializing wallet database environment %s! + %s cüzdan veritabanı ortamının başlatılmasında hata meydana geldi! + + + + Error loading block database + Blok veritabanının yüklenmesinde hata + + + + Error opening block database + Blok veritabanının açılışı sırasında hata + + + + Error: Disk space is low! + Hata: Disk alanı düşük! + + + + Error: Wallet locked, unable to create transaction! + Hata: Cüzdan kilitli, muamele oluşturulamadı! + + + + Error: system error: + Hata: sistem hatası: + + + + Failed to listen on any port. Use -listen=0 if you want this. + Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız. + + + + Failed to read block info + Blok verileri okunamadı + + + + Failed to read block + Blok okunamadı + + + + Failed to sync block index + Blok indeksi eşleştirilemedi + + + + Failed to write block index + Blok indeksi yazılamadı + + + + Failed to write block info + Blok verileri yazılamadı + + + + Failed to write block + Blok yazılamadı + + + + Failed to write file info + Dosya verileri yazılamadı + + + + Failed to write to coin database + Madenî para veritabanına yazılamadı + + + + Failed to write transaction index + Muamele indeksi yazılamadı + + + + Failed to write undo data + Geri alma verilerinin yazılamadı + + + + Find peers using DNS lookup (default: 1 unless -connect) + Eşleri DNS araması vasıtasıyla bul (varsayılan: 1, eğer -connect kullanılmadıysa) + + + + Generate coins (default: 0) + CasinoCoin oluştur (varsayılan: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + Başlangıçta kontrol edilecek blok sayısı (varsayılan: 288, 0 = hepsi) + + + + How thorough the block verification is (0-4, default: 3) + Blok kontrolünün ne kadar derin olacağı (0 ilâ 4, varsayılan: 3) + + + + Not enough file descriptors available. + Kafi derecede dosya tanımlayıcıları mevcut değil. + + + + Rebuild block chain index from current blk000??.dat files + Blok zinciri indeksini güncel blk000??.dat dosyalarından tekrar inşa et + + + + Set the number of threads to service RPC calls (default: 4) + RPC aramaları için iş parçacığı sayısını belirle (varsayılan: 4) + + + + Verifying blocks... + Bloklar kontrol ediliyor... + + + + Verifying wallet... + Cüzdan kontrol ediliyor... + + + + Imports blocks from external blk000??.dat file + Harici blk000??.dat dosyasından blokları içe aktarır + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Betik kontrolü iş parçacığı sayısını belirt (azami 16, 0 = otomatik, <0 = bu sayıda çekirdeği boş bırak, varsayılan: 0) + + + + Information + Bilgi + + + + Invalid -tor address: '%s' + Geçersiz -tor adresi: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + -minrelaytxfee=<amount> için geçersiz meblağ: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + -mintxfee=<amount> için geçersiz meblağ: '%s' + + + + Maintain a full transaction index (default: 0) + Muamelelerin tamamının indeksini tut (varsayılan: 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Bağlantı başına azami alım tamponu, <n>*1000 bayt (varsayılan: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Bağlantı başına azami yollama tamponu, <n>*1000 bayt (varsayılan: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + Sadece yerleşik kontrol noktalarıyla eşleşen blok zincirini kabul et (varsayılan: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Sadece <net> şebekesindeki düğümlere bağlan (IPv4, IPv6 ya da Tor) + + + + Output extra debugging information. Implies all other -debug* options + İlâve hata ayıklama verileri çıkart. Diğer tüm -debug* seçeneklerini ima eder + + + + Output extra network debugging information + İlâve şebeke hata ayıklama verileri çıkart + + + Prepend debug output with timestamp Hata ayıklama çıktısına tarih ön ekleri ilâve et - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL seçenekleri: (SSL kurulum bilgisi için CasinoCoin vikisine bakınız) + + + + Select the version of socks proxy to use (4-5, default: 5) + Kullanılacak socks vekil sunucu sürümünü seç (4-5, varsayılan: 5) + + + Send trace/debug info to console instead of debug.log file Trace/hata ayıklama verilerini debug.log dosyası yerine konsola gönder - + Send trace/debug info to debugger Hata ayıklayıcıya -debugger- trace/hata ayıklama verileri gönder - + + Set maximum block size in bytes (default: 250000) + Bayt olarak azami blok boyutunu tanımla (varsayılan: 250000) + + + + Set minimum block size in bytes (default: 0) + Bayt olarak asgari blok boyutunu tanımla (varsayılan: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + İstemci başlatıldığında debug.log dosyasını küçült (varsayılan: -debug bulunmadığında 1) + + + + Signing transaction failed + Muamelenin imzalanması başarısız oldu + + + + Specify connection timeout in milliseconds (default: 5000) + Bağlantı zaman aşım süresini milisaniye olarak belirt (varsayılan: 5000) + + + + System error: + Sistem hatası: + + + + Transaction amount too small + Muamele meblağı çok düşük + + + + Transaction amounts must be positive + Muamele tutarının pozitif olması lazımdır + + + + Transaction too large + Muamele çok büyük + + + + Use UPnP to map the listening port (default: 0) + Dinlenecek portu haritalamak için UPnP kullan (varsayılan: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde 1) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Gizli tor servislerine erişmek için vekil sunucu kullan (varsayılan: -proxy ile aynısı) + + + Username for JSON-RPC connections JSON-RPC bağlantıları için kullanıcı ismi - + + Warning + Uyarı + + + + Warning: This version is obsolete, upgrade required! + Uyarı: Bu sürüm çok eskidir, güncellemeniz gerekir! + + + + You need to rebuild the databases using -reindex to change -txindex + -txindex'i değiştirmek için veritabanlarını -reindex kullanarak yeniden inşa etmeniz gerekir. + + + + wallet.dat corrupt, salvage failed + wallet.dat bozuk, geri kazanım başarısız oldu + + + Password for JSON-RPC connections JSON-RPC bağlantıları için parola - - Listen for JSON-RPC connections on <port> (default: 8332) - JSON-RPC bağlantıları için dinlenecek <port> (varsayılan: 8332) - - - + Allow JSON-RPC connections from specified IP address Belirtilen İP adresinden JSON-RPC bağlantılarını kabul et - + Send commands to node running on <ip> (default: 127.0.0.1) Şu <ip> adresinde (varsayılan: 127.0.0.1) çalışan düğüme komut yolla - + Execute command when the best block changes (%s in cmd is replaced by block hash) - En iyi blok değiştiğinde komutu çalıştır (cmd için %s blok hash değeri ile değiştirilecektir) + En iyi blok değiştiğinde komutu çalıştır (komut için %s parametresi blok hash değeri ile değiştirilecektir) - + Upgrade wallet to latest format Cüzdanı en yeni biçime güncelle - + Set key pool size to <n> (default: 100) Anahtar alan boyutunu <n> değerine ayarla (varsayılan: 100) - + Rescan the block chain for missing wallet transactions Blok zincirini eksik cüzdan muameleleri için tekrar tara - - How many blocks to check at startup (default: 2500, 0 = all) - Başlangıçta ne kadar blokun denetleneceği (varsayılan: 2500, 0 = tümü) - - - - How thorough the block verification is (0-6, default: 1) - Blok kontrolünün derinliği (0 ilâ 6, varsayılan: 1) - - - - Imports blocks from external blk000?.dat file - Harici blk000?.dat dosyasından blokları içe aktarır - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL seçenekleri: (SSL kurulum bilgisi için Bitcoin vikisine bakınız) - - - + Use OpenSSL (https) for JSON-RPC connections JSON-RPC bağlantıları için OpenSSL (https) kullan - + Server certificate file (default: server.cert) Sunucu sertifika dosyası (varsayılan: server.cert) - + Server private key (default: server.pem) Sunucu özel anahtarı (varsayılan: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Kabul edilebilir şifreler (varsayılan: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - Uyarı: Disk alanı düşük - - - + This help message Bu yardım mesajı - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - %s veri dizininde kilit elde edilemedi. Bitcoin muhtemelen hâlihazırda çalışmaktadır. - - - - Bitcoin - Bitcoin - - - + Unable to bind to %s on this computer (bind returned error %d, %s) Bu bilgisayarda %s unsuruna bağlanılamadı. (bind şu hatayı iletti: %d, %s) - + Connect through socks proxy Socks vekil sunucusu vasıtasıyla bağlan - - Select the version of socks proxy to use (4 or 5, 5 is default) - Kullanılacak socks vekil sunucu sürümünü seç (4 veya 5, ki 5 varsayılan değerdir) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - <net> şebekesi ile bağlantılarda vekil sunucu kullanma (IPv4 ya da IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect -addnode, -seednode ve -connect için DNS aramalarına izin ver - - Pass DNS requests to (SOCKS5) proxy - DNS isteklerini (SOCKS5) vekil sunucusuna devret - - - + Loading addresses... Adresler yükleniyor... - - Error loading blkindex.dat - blkindex.dat dosyasının yüklenmesinde hata oluştu - - - + Error loading wallet.dat: Wallet corrupted wallet.dat dosyasının yüklenmesinde hata oluştu: bozuk cüzdan - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - wallet.dat dosyasının yüklenmesinde hata oluştu: cüzdanın daha yeni bir Bitcoin sürümüne ihtiyacı var + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + wallet.dat dosyasının yüklenmesinde hata oluştu: cüzdanın daha yeni bir CasinoCoin sürümüne ihtiyacı var - - Wallet needed to be rewritten: restart Bitcoin to complete - Cüzdanın tekrar yazılması gerekiyordu: işlemi tamamlamak için Bitcoin'i yeniden başlatınız + + Wallet needed to be rewritten: restart CasinoCoin to complete + Cüzdanın tekrar yazılması gerekiyordu: işlemi tamamlamak için CasinoCoin'i yeniden başlatınız - + Error loading wallet.dat wallet.dat dosyasının yüklenmesinde hata oluştu - + Invalid -proxy address: '%s' Geçersiz -proxy adresi: '%s' - - Unknown network specified in -noproxy: '%s' - -noproxy'de bilinmeyen bir şebeke belirtildi: '%s' - - - + Unknown network specified in -onlynet: '%s' -onlynet için bilinmeyen bir şebeke belirtildi: '%s' - + Unknown -socks proxy version requested: %i Bilinmeyen bir -socks vekil sürümü talep edildi: %i - + Cannot resolve -bind address: '%s' -bind adresi çözümlenemedi: '%s' - - Not listening on any port - Hiçbir port dinlenmiyor - - - + Cannot resolve -externalip address: '%s' -externalip adresi çözümlenemedi: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<miktar> için geçersiz miktar: '%s' - - Error: could not start node - Hata: düğüm başlatılamadı - - - - Error: Wallet locked, unable to create transaction - Hata: Cüzdan kilitli, muamele oluşturulamadı - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - Hata: Muamelenin miktarı, karmaşıklığı ya da yakın geçmişte alınan fonların kullanılması nedeniyle bu muamele en az %s tutarında ücret gerektirmektedir - - - - Error: Transaction creation failed - Hata: Muamele oluşturması başarısız oldu - - - - Sending... - Gönderiliyor... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Hata: Muamele reddedildi. Cüzdanınızdaki madenî paraların bazıları zaten harcanmış olduğunda bu meydana gelebilir. Örneğin wallet.dat dosyasının bir kopyasını kullandıysanız ve kopyada para harcandığında ancak burada harcandığı işaretlenmediğinde. - - - + Invalid amount Geçersiz miktar - + Insufficient funds Yetersiz bakiye - + Loading block index... Blok indeksi yükleniyor... - + Add a node to connect to and attempt to keep the connection open Bağlanılacak düğüm ekle ve bağlantıyı zinde tutmaya çalış - - Unable to bind to %s on this computer. Bitcoin is probably already running. - Bu bilgisayarda %s unsuruna bağlanılamadı. Bitcoin muhtemelen hâlihazırda çalışmaktadır. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Bu bilgisayarda %s unsuruna bağlanılamadı. CasinoCoin muhtemelen hâlihazırda çalışmaktadır. - - Find peers using internet relay chat (default: 0) - Eşleri Internet Relay Chat vasıtasıyla bul (varsayılan: 0) - - - - Accept connections from outside (default: 1) - Dışarıdan gelen bağlantıları kabul et (varsayılan: 1) - - - - Find peers using DNS lookup (default: 1) - Eşleri DNS araması vasıtasıyla bul (varsayılan: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - Dinlenecek portu haritalamak için Universal Plug and Play kullan (varsayılan: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - Dinlenecek portu haritalamak için Universal Plug and Play kullan (varsayılan: 0) - - - + Fee per KB to add to transactions you send Yolladığınız muameleler için eklenecek KB başı ücret - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - Uyarı: -paytxfee çok yüksek bir değere ayarlanmış. Bu, muamele gönderirseniz ödeyeceğiniz muamele ücretidir. - - - + Loading wallet... Cüzdan yükleniyor... - + Cannot downgrade wallet Cüzdan eski biçime geri alınamaz - - Cannot initialize keypool - Keypool başlatılamadı - - - + Cannot write default address Varsayılan adres yazılamadı - + Rescanning... Yeniden tarama... - + Done loading Yükleme tamamlandı - + To use the %s option %s seçeneğini kullanmak için - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, şu yapılandırma dosyasında rpc parolası belirtmeniz gerekir: - %s -Aşağıdaki rastgele oluşturulan parolayı kullanmanız tavsiye edilir: -rpcuser=bitcoinrpc -rpcpassword=%s -(bu parolayı hatırlamanız gerekli değildir) -Dosya mevcut değilse, sadece sahibi için okumayla sınırlı izin ile oluşturunuz. - - - - + Error Hata - - An error occured while setting up the RPC port %i for listening: %s - %i RPC portunun dinleme için kurulması sırasında bir hata meydana geldi: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2511,10 +2934,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s Dosya mevcut değilse, sadece sahibi için okumayla sınırlı izin ile oluşturunuz. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Uyarı: Lütfen bilgisayarınızın tarih ve saatinin doğru olup olmadığını kontrol ediniz. Saatiniz doğru değilse Bitcoin gerektiği gibi çalışamaz. - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index bf41f51..8ea5dc8 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - Про Bitcoin + + About CasinoCoin + Про CasinoCoin - - <b>Bitcoin</b> version - Версія <b>Bitcoin'a<b> + + <b>CasinoCoin</b> version + Версія <b>CasinoCoin'a<b> - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - Авторське право © 2009-2012 Розробники Bitcoin - + Це програмне забезпечення є експериментальним. -Поширюється за ліцензією MIT/X11, додаткова інформація міститься у файлі license.txt, а також за адресою http://www.opensource.org/licenses/mit-license.php. +Поширюється за ліцензією MIT/X11, додаткова інформація міститься у файлі COPYING, а також за адресою http://www.opensource.org/licenses/mit-license.php. Цей продукт включає в себе програмне забезпечення, розроблене в рамках проекту OpenSSL (http://www.openssl.org/), криптографічне програмне забезпечення, написане Еріком Янгом (eay@cryptsoft.com), та функції для роботи з UPnP, написані Томасом Бернардом. + + + Copyright + Авторське право + + + + The CasinoCoin developers + + AddressBookPage - + Address Book Адресна книга - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Це ваші адреси для отримання платежів. Ви можете давати різні адреси різним людям, таким чином маючи можливість відслідкувати хто конкретно і скільки вам заплатив. - - - + Double-click to edit address or label Двічі клікніть на адресу чи назву для їх зміни - + Create a new address Створити нову адресу - + Copy the currently selected address to the system clipboard Копіювати виділену адресу в буфер обміну - + &New Address - + &Створити адресу - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Це ваші адреси для отримання платежів. Ви можете давати різні адреси різним людям, таким чином маючи можливість відслідкувати хто конкретно і скільки вам заплатив. + + + &Copy Address - + &Скопіювати адресу - + Show &QR Code Показати QR-&Код - - Sign a message to prove you own this address + + Sign a message to prove you own a CasinoCoin address Підпишіть повідомлення щоб довести, що ви є власником цієї адреси - - &Sign Message + + Sign &Message &Підписати повідомлення - - Delete the currently selected address from the list. Only sending addresses can be deleted. - Видалити виділену адресу зі списку. Лише адреси з адресної книги можуть бути видалені. + + Delete the currently selected address from the list + Вилучити вибрані адреси з переліку - + + Export the data in the current tab to a file + Експортувати дані з поточної вкладки в файл + + + + &Export + + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + Перевірте повідомлення для впевненості, що воно підписано вказаною CasinoCoin-адресою + + + + &Verify Message + Перевірити повідомлення + + + &Delete &Видалити - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + Copy &Label - + Скопіювати &мітку - + &Edit + &Редагувати + + + + Send &Coins - + Export Address Book Data Експортувати адресну книгу - + Comma separated file (*.csv) Файли відділені комами (*.csv) - + Error exporting Помилка при експортуванні - + Could not write to file %1. Неможливо записати у файл %1. @@ -126,17 +164,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label Назва - + Address Адреса - + (no label) (немає назви) @@ -144,432 +182,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog - + Діалог введення паролю - + Enter passphrase Введіть пароль - + New passphrase Новий пароль - + Repeat new passphrase Повторіть пароль - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - Введіть новий пароль для гаманця.<br/>Будь ласка, використовуйте паролі що містять <b> як мінімум 10 випадкових символів </b> або <b> як мінімум 8 слів</b>. + Введіть новий пароль для гаманця.<br/>Будь ласка, використовуйте паролі що містять <b>як мінімум 10 випадкових символів</b>, або <b>як мінімум 8 слів</b>. - + Encrypt wallet Зашифрувати гаманець - + This operation needs your wallet passphrase to unlock the wallet. Ця операція потребує пароль для розблокування гаманця. - + Unlock wallet Розблокувати гаманець - + This operation needs your wallet passphrase to decrypt the wallet. Ця операція потребує пароль для дешифрування гаманця. - + Decrypt wallet Дешифрувати гаманець - + Change passphrase Змінити пароль - + Enter the old and new passphrase to the wallet. Ввести старий та новий паролі для гаманця. - + Confirm wallet encryption Підтвердити шифрування гаманця - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - УВАГА: Якщо ви зашифруєте гаманець і забудете пароль, ви <b>ВТРАТИТЕ ВСІ СВОЇ БІТКОІНИ</b>! -Ви дійсно хочете зашифрувати свій гаманець? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + УВАГА: Якщо ви зашифруєте гаманець і забудете пароль, ви <b>ВТРАТИТЕ ВСІ СВОЇ БІТКОІНИ</b>! - - + + Are you sure you wish to encrypt your wallet? + Ви дійсно хочете зашифрувати свій гаманець? + + + + 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. + + + + + + Warning: The Caps Lock key is on! + Увага: Ввімкнено Caps Lock! + + + + Wallet encrypted Гаманець зашифровано - - Bitcoin 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. - Біткоін-клієнт буде закрито для завершення процесу шифрування. Пам’ятайте, що шифрування гаманця не може повністю захистити ваші біткоіни від кражі, у випадку якщо ваш комп’ютер буде інфіковано шкідливими програмами. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + Біткоін-клієнт буде закрито для завершення процесу шифрування. Пам'ятайте, що шифрування гаманця не може повністю захистити ваші біткоіни від крадіжки, у випадку якщо ваш комп'ютер буде інфіковано шкідливими програмами. - - - Warning: The Caps Lock key is on. - Увага: Ввімкнено Caps Lock - - - - - - + + + + Wallet encryption failed Не вдалося зашифрувати гаманець - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Виникла помилка під час шифрування гаманця. Ваш гаманець не було зашифровано. - - + + The supplied passphrases do not match. Введені паролі не співпадають. - + Wallet unlock failed Не вдалося розблокувати гаманець - - - + + + The passphrase entered for the wallet decryption was incorrect. Введений пароль є невірним. - + Wallet decryption failed Не вдалося розшифрувати гаманець - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. Пароль було успішно змінено. BitcoinGUI - - Bitcoin Wallet - Гаманець - - - + Sign &message... - + &Підписати повідомлення... - - Show/Hide &Bitcoin - - - - + Synchronizing with network... Синхронізація з мережею... - + &Overview &Огляд - + Show general overview of wallet Показати загальний огляд гаманця - + &Transactions - Пе&реклади + Транзакції - + Browse transaction history - Переглянути історію переказів + Переглянути історію транзакцій - - &Address Book - &Адресна книга - - - + Edit the list of stored addresses and labels Редагувати список збережених адрес та міток - - &Receive coins - О&тримати - - - + Show the list of addresses for receiving payments Показати список адрес для отримання платежів - - &Send coins - В&ідправити - - - - Prove you control an address - Доведіть, що це ваша адреса - - - + E&xit &Вихід - + Quit application Вийти - - &About %1 - П&ро %1 + + Show information about CasinoCoin + Показати інформацію про CasinoCoin - - Show information about Bitcoin - Показати інформацію про Bitcoin - - - + About &Qt &Про Qt - + Show information about Qt Показати інформацію про Qt - + &Options... &Параметри... - + &Encrypt Wallet... - + &Шифрування гаманця... - + &Backup Wallet... - + &Резервне копіювання гаманця... - + &Change Passphrase... - - - - - ~%n block(s) remaining - + Змінити парол&ь... - - Downloaded %1 of %2 blocks of transaction history (%3% done). + + Importing blocks from disk... + Імпорт блоків з диску... + + + + Reindexing blocks on disk... - - &Export... - &Експорт... + + Send coins to a CasinoCoin address + Відправити монети на вказану адресу - - Send coins to a Bitcoin address - + + Modify configuration options for CasinoCoin + Редагувати параметри - - Modify configuration options for Bitcoin - - - - - Show or hide the Bitcoin window - - - - - Export the data in the current tab to a file - Експортувати дані з поточної вкладки в файл - - - - Encrypt or decrypt wallet - Зашифрувати чи розшифрувати гаманець - - - + Backup wallet to another location Резервне копіювання гаманця в інше місце - + Change the passphrase used for wallet encryption Змінити пароль, який використовується для шифрування гаманця - + &Debug window - + Вікно зневадження - + Open debugging and diagnostic console - + Відкрити консоль зневадження і діагностики - + &Verify message... + Перевірити повідомлення... + + + + + CasinoCoin + CasinoCoin + + + + Wallet + Гаманець + + + + &Send - - Verify a message signature + + &Receive - + + &Addresses + + + + + &About CasinoCoin + &Про CasinoCoin + + + + &Show / Hide + Показати / Приховати + + + + Show or hide the main Window + Показує або приховує головне вікно + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your CasinoCoin addresses to prove you own them + Підтвердіть, що Ви є власником повідомлення підписавши його Вашою CasinoCoin-адресою + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + Перевірте повідомлення для впевненості, що воно підписано вказаною CasinoCoin-адресою + + + &File &Файл - + &Settings &Налаштування - + &Help &Довідка - + Tabs toolbar Панель вкладок - - Actions toolbar - Панель дій - - - - + + [testnet] [тестова мережа] - - - Bitcoin client + + CasinoCoin client + CasinoCoin-клієнт + + + + %n active connection(s) to CasinoCoin network + %n активне з'єднання з мережею%n активні з'єднання з мережею%n активних з'єднань з мережею + + + + No block source available... - - - %n active connection(s) to Bitcoin network - %n активне з’єднання з мережею%n активні з’єднання з мережею%n активних з’єднань з мережею + + + Processed %1 of %2 (estimated) blocks of transaction history. + - - Downloaded %1 blocks of transaction history. - Завантажено %1 блоків історії транзакцій. + + Processed %1 blocks of transaction history. + Оброблено %1 блоків історії транзакцій. - - %n second(s) ago - %n секунду тому%n секунди тому%n секунд тому + + %n hour(s) + - - %n minute(s) ago - %n хвилину тому%n хвилини тому%n хвилин тому + + %n day(s) + - - %n hour(s) ago - %n годину тому%n години тому%n годин тому - - - - %n day(s) ago - %n день тому%n дня тому%n днів тому + + %n week(s) + - + + %1 behind + + + + + Last received block was generated %1 ago. + + + + + Transactions after this will not yet be visible. + + + + + Error + Помилка + + + + Warning + Увага + + + + Information + Інформація + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + Up to date Синхронізовано - + Catching up... Синхронізується... - - Last received block was generated %1. - Останній отриманий блок було згенеровано %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - Цей переказ перевищує максимально допустимий розмір. Проте ви можете здійснити її, додавши комісію в %1, яка відправиться тим вузлам що оброблять ваш переказ, та допоможе підтримати мережу. Ви хочете додати комісію? - - - + Confirm transaction fee - + Підтвердити комісію - + Sent transaction - Надіслані перекази + Надіслані транзакції - + Incoming transaction Отримані перекази - + Date: %1 Amount: %2 Type: %3 @@ -582,539 +648,485 @@ Address: %4 - + + + URI handling + Обробка URI + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + Неможливо обробити URI! Це може бути викликано неправильною CasinoCoin-адресою, чи невірними параметрами URI. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> <b>Зашифрований</b> гаманець <b>розблоковано</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> <b>Зашифрований</b> гаманець <b>заблоковано</b> - - Backup Wallet - Резервне копіювання гаманця - - - - Wallet Data (*.dat) - Дані гаманця (*.dat) - - - - Backup Failed - Резервне копіювання не вдалося - - - - There was an error trying to save the wallet data to the new location. - Виникла помилка при спробі зберегти гаманець в новому місці - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. ClientModel - + Network Alert - - - - - DisplayOptionsPage - - - Display - Відображення - - - - default - - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - - - - - User Interface &Language: - - - - - &Unit to show amounts in: - - - - - Choose the default subdivision unit to show in the interface, and when sending coins - Виберіть одиницю вимірювання монет, яка буде відображатись в гаманці та при відправленні. - - - - &Display addresses in transaction list - - - - - Whether to show Bitcoin addresses in the transaction list - - - - - Warning - - - - - This setting will take effect after restarting Bitcoin. - + Сповіщення мережі EditAddressDialog - + Edit Address Редагувати адресу - + &Label &Мітка - + The label associated with this address book entry - Мітка, пов’язана з цим записом адресної книги + Мітка, пов'язана з цим записом адресної книги - + &Address &Адреса - + The address associated with this address book entry. This can only be modified for sending addresses. - Адреса, пов’язана з цим записом адресної книги. + Адреса, пов'язана з цим записом адресної книги. Може бути змінено тільки для адреси відправника. - + New receiving address Нова адреса для отримання - + New sending address Нова адреса для відправлення - + Edit receiving address Редагувати адресу для отримання - + Edit sending address Редагувати адресу для відправлення - + The entered address "%1" is already in the address book. Введена адреса «%1» вже присутня в адресній книзі. - - The entered address "%1" is not a valid Bitcoin address. - + + The entered address "%1" is not a valid CasinoCoin address. + Введена адреса «%1» не є коректною адресою в мережі CasinoCoin. - + Could not unlock wallet. Неможливо розблокувати гаманець. - + New key generation failed. Не вдалося згенерувати нові ключі. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - + + + CasinoCoin-Qt + CasinoCoin-Qt - + version - + версія - + Usage: - Вкористання: + Використання: - - options - + + command-line options + параметри командного рядка - + UI options - + Параметри інтерфейсу - + Set language, for example "de_DE" (default: system locale) - + Встановлення мови, наприклад "de_DE" (типово: системна) - + Start minimized - Запускати згорнутим - + Запускати згорнутим - + Show splash screen on startup (default: 1) - - - - - MainOptionsPage - - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - - - - - Pay transaction &fee - Заплатити комісі&ю - - - - Main - Головні - - - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Добровільна комісія за кожен Кб переказу, яка дозволяє бути впевненим у тому, що ваш переказ буде оброблено швидко. Розмір більшості переказів рівен 1 Кб. Рекомендована комісія: 0,01. - - - - &Start Bitcoin on system login - - - - - Automatically start Bitcoin after logging in to the system - - - - - &Detach databases at shutdown - - - - - MessagePage - - - Sign Message - - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - Choose adress from address book - Вибрати адресу з адресної книги - - - - Alt+A - Alt+A - - - - Paste address from clipboard - Вставити адресу - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - Введіть повідомлення, яке ви хочете підписати тут - - - - Copy the current signature to the system clipboard - - - - - &Copy Signature - - - - - Reset all sign message fields - - - - - Clear &All - - - - - Click "Sign Message" to get signature - Натисніть кнопку "Підписати повідомлення", для отриманя підпису - - - - Sign a message to prove you own this address - Підпишіть повідомлення щоб довести, що ви є власником цієї адреси - - - - &Sign Message - &Підписати повідомлення - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Введіть адресу Bitcoin (наприклад 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - Помилка при підписуванні - - - - %1 is not a valid address. - "%1" не є коректною адресою в мережі Bitcoin. - - - - %1 does not refer to a key. - - - - - Private key for %1 is not available. - Приватний ключ для %1 недоступний. - - - - Sign failed - Не вдалось підписати - - - - NetworkOptionsPage - - - Network - - - - - Map port using &UPnP - Відображення порту через &UPnP - - - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Автоматично відкривати порт для клієнту біткоін на роутері. Працює лише якщо ваш роутер підтримує UPnP і ця функція увімкнена. - - - - &Connect through SOCKS4 proxy: - Підключатись через &SOCKS4-проксі: - - - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - Підключатись до мережі Bitcoin через SOCKS4-проксі (наприклад при використанні Tor) - - - - Proxy &IP: - - - - - &Port: - - - - - IP address of the proxy (e.g. 127.0.0.1) - IP-адреса проксі-сервера (наприклад 127.0.0.1) - - - - Port of the proxy (e.g. 1234) - Порт проксі-сервера (наприклад 1234) + Показувати заставку під час запуску (типово: 1) OptionsDialog - + Options Параметри + + + &Main + &Головні + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + Заплатити комісі&ю + + + + Automatically start CasinoCoin after logging in to the system. + Автоматично запускати гаманець при вході до системи. + + + + &Start CasinoCoin on system login + &Запускати гаманець при вході в систему + + + + Reset all client options to default. + Скинути всі параметри клієнта на типові. + + + + &Reset Options + Скинути параметри + + + + &Network + &Мережа + + + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + Автоматично відкривати порт для клієнту біткоін на роутері. Працює лише якщо ваш роутер підтримує UPnP і ця функція увімкнена. + + + + Map port using &UPnP + Відображення порту через &UPnP + + + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + Підключатись до мережі CasinoCoin через SOCKS-проксі (наприклад при використанні Tor). + + + + &Connect through SOCKS proxy: + Підключатись через &SOCKS-проксі: + + + + Proxy &IP: + &IP проксі: + + + + IP address of the proxy (e.g. 127.0.0.1) + IP-адреса проксі-сервера (наприклад 127.0.0.1) + + + + &Port: + &Порт: + + + + Port of the proxy (e.g. 9050) + Порт проксі-сервера (наприклад 9050) + + + + SOCKS &Version: + SOCKS версії: + + + + SOCKS version of the proxy (e.g. 5) + Версія SOCKS-проксі (наприклад 5) + + + + &Window + &Вікно + + + + Show only a tray icon after minimizing the window. + Показувати лише іконку в треї після згортання вікна. + + + + &Minimize to the tray instead of the taskbar + Мінімізувати &у трей + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Згортати замість закриття. Якщо ця опція включена, програма закриється лише після вибору відповідного пункту в меню. + + + + M&inimize on close + Згортати замість закритт&я + + + + &Display + &Відображення + + + + User Interface &language: + Мова інтерфейсу користувача: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + Встановлює мову інтерфейсу. Зміни набудуть чинності після перезапуску CasinoCoin. + + + + &Unit to show amounts in: + В&имірювати монети в: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Виберіть одиницю вимірювання монет, яка буде відображатись в гаманці та при відправленні. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + &Відображати адресу в списку транзакцій + + + + &OK + &Гаразд + + + + &Cancel + &Скасувати + + + + &Apply + &Застосувати + + + + default + типово + + + + Confirm options reset + Підтвердження скидання параметрів + + + + Some settings may require a client restart to take effect. + Деякі параметри потребують перезапуск клієнта для набуття чинності. + + + + Do you want to proceed? + Продовжувати? + + + + + Warning + Увага + + + + + This setting will take effect after restarting CasinoCoin. + Цей параметр набуде чинності після перезапуску CasinoCoin. + + + + The supplied proxy address is invalid. + Невірно вказано адресу проксі. + OverviewPage - + Form Форма - - - 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. - + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + Показана інформація вже може бути застарілою. Ваш гаманець буде автоматично синхронізовано з мережею CasinoCoin після встановлення підключення, але цей процес ще не завершено. - + Balance: Баланс: - - Number of transactions: - Кількість переказів: - - - + Unconfirmed: Непідтверджені: - + Wallet + Гаманець + + + + Immature: - - <b>Recent transactions</b> - <b>Недавні перекази</b> + + Mined balance that has not yet matured + - + + <b>Recent transactions</b> + <b>Недавні транзакції</b> + + + Your current balance Ваш поточний баланс - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance - Загальна сума всіх переказів, які ще не підтверджені, та до сих пір не враховуються в загальному балансі + Загальна сума всіх транзакцій, які ще не підтверджені, та до цих пір не враховуються в загальному балансі - - Total number of transactions in wallet - Загальна кількість переказів в гаманці - - - - + + out of sync + не синхронізовано + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler QRCodeDialog - + QR Code Dialog - + Діалог QR-коду - - QR Code - QR-Код - - - + Request Payment Запросити Платіж - + Amount: Кількість: - - BTC - BTC - - - + Label: Мітка: - + Message: Повідомлення: - + &Save As... &Зберегти як... - + Error encoding URI into QR Code. - + Помилка при кодуванні URI в QR-код. - + + The entered amount is invalid, please check. + Невірно введено кількість, будь ласка, перевірте. + + + Resulting URI too long, try to reduce the text for label / message. - + Кінцевий URI занадто довгий, спробуйте зменшити текст для мітки / повідомлення. - + Save QR Code - + Зберегти QR-код - + PNG Images (*.png) PNG-зображення (*.png) @@ -1122,571 +1134,831 @@ Address: %4 RPCConsole - - Bitcoin debug window - - - - + Client name - + Назва клієнту - - - - - - - - - + + + + + + + + + + N/A - + Н/Д - + Client version - + Версія клієнту - + &Information - + &Інформація - - Client - + + Using OpenSSL version + Використовується OpenSSL версії - + Startup time - + Network - + Мережа - + Number of connections - + Кількість підключень - + On testnet - + В тестовій мережі - + Block chain - + Current number of blocks - + Поточне число блоків - + Estimated total blocks - + Last block time - - Debug logfile - - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - - - - + &Open - + Відкрити - + + Command-line options + Параметри командного рядка + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + Показати довідку CasinoCoin-Qt для отримання переліку можливих параметрів командного рядка. + + + + &Show + Показати + + + &Console - + Консоль - + Build date + Дата збирання + + + + CasinoCoin - Debug window + CasinoCoin - Вікно зневадження + + + + CasinoCoin Core - + + Debug log file + Файл звіту зневадження + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console - + Очистити консоль - - Welcome to the Bitcoin RPC console. - + + Welcome to the CasinoCoin RPC console. + Вітаємо у консолі CasinoCoin RPC. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Використовуйте стрілки вгору вниз для навігації по історії, і <b>Ctrl-L</b> для очищення екрана. - + Type <b>help</b> for an overview of available commands. - + Наберіть <b>help</b> для перегляду доступних команд. SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins Відправити - + Send to multiple recipients at once Відправити на декілька адрес - - &Add Recipient - + + Add &Recipient + Дод&ати одержувача - + Remove all transaction fields Видалити всі поля транзакції - + Clear &All - + Очистити &все - + Balance: Баланс: - + 123.456 BTC 123.456 BTC - + Confirm the send action Підтвердити відправлення - - &Send + + S&end &Відправити - + <b>%1</b> to %2 (%3) <b>%1</b> адресату %2 (%3) - + Confirm send coins Підтвердіть відправлення - + Are you sure you want to send %1? - Ви впевнені що хочете відправити %1 + Ви впевнені що хочете відправити %1? - + and і - - The recepient address is not valid, please recheck. - Адреса отримувача невірна, будьласка перепровірте. + + The recipient address is not valid, please recheck. + Адреса отримувача невірна, будь ласка перепровірте. - + The amount to pay must be larger than 0. Кількість монет для відправлення повинна бути більшою 0. - + The amount exceeds your balance. - + Кількість монет для відправлення перевищує ваш баланс. - + The total exceeds your balance when the %1 transaction fee is included. - + Сума перевищить ваш баланс, якщо комісія %1 буде додана до вашої транзакції. - + Duplicate address found, can only send to each address once per send operation. - + Знайдено адресу що дублюється. Відправлення на кожну адресу дозволяється лише один раз на кожну операцію переказу. - - Error: Transaction creation failed. - + + Error: Transaction creation failed! + Помилка: Не вдалося створити транзакцію! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Помилка: транзакцію було відхилено. Це може статись, якщо декілька монет з вашого гаманця вже використані, наприклад, якщо ви використовуєте одну копію гаманця (wallet.dat), а монети були використані з іншої копії, але не позначені як використані в цій. SendCoinsEntry - + Form Форма - + A&mount: &Кількість: - + Pay &To: &Отримувач: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Enter a label for this address to add it to your address book Введіть мітку для цієї адреси для додавання її в адресну книгу - + &Label: &Мітка: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Адреса для отримувача платежу (наприклад, 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book Вибрати адресу з адресної книги - + Alt+A Alt+A - + Paste address from clipboard Вставити адресу - + Alt+P Alt+P - + Remove this recipient Видалити цього отримувача - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - Введіть адресу Bitcoin (наприклад 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Введіть адресу CasinoCoin (наприклад Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Підписи - Підпис / Перевірка повідомлення + + + + &Sign Message + &Підписати повідомлення + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Введіть адресу CasinoCoin (наприклад Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + Вибрати адресу з адресної книги + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Вставити адресу + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Введіть повідомлення, яке ви хочете підписати тут + + + + Signature + Підпис + + + + Copy the current signature to the system clipboard + Копіювати поточну сигнатуру до системного буферу обміну + + + + Sign the message to prove you own this CasinoCoin address + Підпишіть повідомлення щоб довести, що ви є власником цієї адреси + + + + Sign &Message + &Підписати повідомлення + + + + Reset all sign message fields + Скинути всі поля підпису повідомлення + + + + + Clear &All + Очистити &все + + + + &Verify Message + Перевірити повідомлення + + + + Enter the signing 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. + + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Введіть адресу CasinoCoin (наприклад Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + Перевірте повідомлення для впевненості, що воно підписано вказаною CasinoCoin-адресою + + + + Verify &Message + Перевірити повідомлення + + + + Reset all verify message fields + Скинути всі поля перевірки повідомлення + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + Введіть адресу CasinoCoin (наприклад Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + Натисніть кнопку «Підписати повідомлення», для отримання підпису + + + + Enter CasinoCoin signature + Введіть сигнатуру CasinoCoin + + + + + The entered address is invalid. + Введена нечинна адреса. + + + + + + + Please check the address and try again. + Будь ласка, перевірте адресу та спробуйте ще. + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + Не вдалося підписати повідомлення. + + + + Message signed. + Повідомлення підписано. + + + + The signature could not be decoded. + Підпис не можливо декодувати. + + + + + Please check the signature and try again. + Будь ласка, перевірте підпис та спробуйте ще. + + + + The signature did not match the message digest. + + + + + Message verification failed. + Не вдалося перевірити повідомлення. + + + + Message verified. + Повідомлення перевірено. + + + + SplashScreen + + + The CasinoCoin developers + + + + + [testnet] + [тестова мережа] TransactionDesc - - Open for %1 blocks - Відкрити для %1 блоків - - - + Open until %1 Відкрити до %1 - - %1/offline? - %1/поза інтернетом? + + %1/offline + %1/поза інтернетом - + %1/unconfirmed %1/не підтверджено - + %1 confirmations %1 підтверджень - - <b>Status:</b> - <b>Статус:</b> + + Status + Статус + + + + , broadcast through %n node(s) + - + + Date + Дата + + + + Source + + + + + Generated + Згенеровано + + + + + From + Відправник + + + + + + To + Отримувач + + + + + own address + + + + + label + Мітка + + + + + + + + Credit + Кредит + + + + matures in %n more block(s) + + + + + not accepted + не прийнято + + + + + + + Debit + Дебет + + + + Transaction fee + Комісія за транзакцію + + + + Net amount + Загальна сума + + + + Message + Повідомлення + + + + Comment + Коментар + + + + Transaction ID + ID транзакції + + + + Generated coins must mature 120 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. + Після генерації монет, потрібно зачекати 120 блоків, перш ніж їх можна буде використати. Коли ви згенерували цей блок, його було відправлено в мережу для того, щоб він був доданий до ланцюжка блоків. Якщо ця процедура не вдасться, статус буде змінено на «не підтверджено» і ви не зможете потратити згенеровані монету. Таке може статись, якщо хтось інший згенерував блок на декілька секунд раніше. + + + + Debug information + + + + + Transaction + Транзакція + + + + Inputs + + + + + Amount + Кількість + + + + true + true + + + + false + false + + + , has not been successfully broadcast yet , ще не було успішно розіслано - - - , broadcast through %1 node - , розіслано через %1 вузол + + + Open for %n more block(s) + - - , broadcast through %1 nodes - , розіслано через %1 вузлів - - - - <b>Date:</b> - <b>Дата:</b> - - - - <b>Source:</b> Generated<br> - <b>Джерело:</b> згенеровано<br> - - - - - <b>From:</b> - <b>Відправник:</b> - - - + unknown невідомий - - - - - <b>To:</b> - <b>Одержувач:</b> - - - - (yours, label: - (Ваша, мітка: - - - - (yours) - (ваша) - - - - - - - <b>Credit:</b> - <b>Кредит:</b> - - - - (%1 matures in %2 more blocks) - (%1 «дозріє» через %2 блоків) - - - - (not accepted) - (не прийнято) - - - - - - <b>Debit:</b> - <b>Дебет:</b> - - - - <b>Transaction fee:</b> - <b>Комісія за переказ:</b> - - - - <b>Net amount:</b> - <b>Загальна сума:</b> - - - - Message: - Повідомлення: - - - - Comment: - Коментар: - - - - Transaction ID: - ID транзакції: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - Після генерації монет, потрібно зачекати 120 блоків, перш ніж їх можна буде використати. Коли ви згенерували цей блок, його було відправлено в мережу для того, щоб він був доданий до ланцюжка блоків. Якщо ця процедура не вдасться, статус буде змінено на «не підтверджено» і ви не зможете потратити згенеровані монету. Таке може статись, якщо хтось інший згенерував блок на декілька секунд раніше. - TransactionDescDialog - + Transaction details - Деталі переказів + Деталі транзакції - + This pane shows a detailed description of the transaction - Даний діалог показує детальну статистику по вибраному переказу + Даний діалог показує детальну статистику по вибраній транзакції TransactionTableModel - + Date Дата - + Type Тип - + Address Адреса - + Amount Кількість - - Open for %n block(s) - Відкрити для %n блокуВідкрити для %n блоківВідкрити для %n блоків + + Open for %n more block(s) + - + Open until %1 Відкрити до %1 - + Offline (%1 confirmations) Поза інтернетом (%1 підтверджень) - + Unconfirmed (%1 of %2 confirmations) Непідтверджено (%1 із %2 підтверджень) - + Confirmed (%1 confirmations) Підтверджено (%1 підтверджень) - - Mined balance will be available in %n more blocks - Добутими монетами можна буде скористатись через %n блокДобутими монетами можна буде скористатись через %n блокиДобутими монетами можна буде скористатись через %n блоків + + Mined balance will be available when it matures in %n more block(s) + - + This block was not received by any other nodes and will probably not be accepted! Цей блок не був отриманий жодними іншими вузлами і, ймовірно, не буде прийнятий! - + Generated but not accepted Згенеровано, але не підтверджено - + Received with Отримано - + Received from Отримано від - + Sent to Відправлено - + Payment to yourself Відправлено собі - + Mined Добуто - + (n/a) (недоступно) - + Transaction status. Hover over this field to show number of confirmations. - Статус переказу. Наведіть вказівник на це поле, щоб показати кількість підтверджень. + Статус транзакції. Наведіть вказівник на це поле, щоб показати кількість підтверджень. - + Date and time that the transaction was received. - Дата і час, коли переказ було отримано. + Дата і час, коли транзакцію було отримано. - + Type of transaction. - Тип переказу. + Тип транзакції. - + Destination address of transaction. - Адреса отримувача + Адреса отримувача транзакції. - + Amount removed from or added to balance. Сума, додана чи знята з балансу. @@ -1694,847 +1966,963 @@ Address: %4 TransactionView - - + + All Всі - + Today Сьогодні - + This week На цьому тижні - + This month На цьому місяці - + Last month Минулого місяця - + This year Цього року - + Range... - Проміжок + Проміжок... - + Received with Отримані на - + Sent to Відправлені на - + To yourself Відправлені собі - + Mined Добуті - + Other Інше - + Enter address or label to search Введіть адресу чи мітку для пошуку - + Min amount Мінімальна сума - + Copy address Скопіювати адресу - + Copy label Скопіювати мітку - + Copy amount Копіювати кількість - + + Copy transaction ID + + + + Edit label Редагувати мітку - + Show transaction details - + Показати деталі транзакції - + Export Transaction Data - Експортувати дані переказів + Експортувати дані транзакцій - + Comma separated file (*.csv) Файли, розділені комою (*.csv) - + Confirmed Підтверджені - + Date Дата - + Type Тип - + Label Мітка - + Address Адреса - + Amount Кількість - + ID Ідентифікатор - + Error exporting Помилка експорту - + Could not write to file %1. - Неможливо записати у файл %1 + Неможливо записати у файл %1. - + Range: Діапазон від: - + to до - - VerifyMessageDialog - - - Verify Signed Message - - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - - - - - Verify a message and obtain the Bitcoin address used to sign the message - - - - - &Verify Message - - - - - Copy the currently selected address to the system clipboard - Копіювати виділену адресу в буфер обміну - - - - &Copy Address - - - - - Reset all verify message fields - - - - - Clear &All - - - - - Enter Bitcoin signature - - - - - Click "Verify Message" to obtain address - - - - - - Invalid Signature - - - - - The signature could not be decoded. Please check the signature and try again. - - - - - The signature did not match the message digest. Please check the signature and try again. - - - - - Address not found in address book. - - - - - Address found in address book: %1 - - - WalletModel - - Sending... - Відправка... + + Send Coins + Відправити - WindowOptionsPage + WalletView - - Window + + &Export - - &Minimize to the tray instead of the taskbar - Мінімізувати &у трей + + Export the data in the current tab to a file + Експортувати дані з поточної вкладки в файл - - Show only a tray icon after minimizing the window - Показувати лише іконку в треї після згортання вікна - - - - M&inimize on close + + Backup Wallet - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - Згортати замість закриття. Якщо ця опція включена, програма закриється лише після вибору відповідного пункту в меню. + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + Виникла помилка при спробі зберегти гаманець в новому місці. + + + + Backup Successful + Успішне створення резервної копії + + + + The wallet data was successfully saved to the new location. + Данні гаманця успішно збережено в новому місці призначення. bitcoin-core - - Bitcoin version + + CasinoCoin version Версія - + Usage: - Вкористання: + Використання: - - Send command to -server or bitcoind - Відправити команду серверу -server чи демону - + + Send command to -server or casinocoind + Відправити команду серверу -server чи демону - + List commands - Список команд - + Список команд - + Get help for a command - Отримати довідку по команді - + Отримати довідку по команді - + Options: - Параметри: - + Параметри: - - Specify configuration file (default: bitcoin.conf) - Вкажіть файл конфігурації (за промовчуванням: bitcoin.conf) - + + Specify configuration file (default: casinocoin.conf) + Вкажіть файл конфігурації (типово: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - Вкажіть pid-файл (за промовчуванням: bitcoind.pid) - + + Specify pid file (default: casinocoind.pid) + Вкажіть pid-файл (типово: casinocoind.pid) - - Generate coins - Генерувати монети - - - - - Don't generate coins - Не генерувати монети - - - - + Specify data directory - Вкажіть робочий каталог - + Вкажіть робочий каталог - + Set database cache size in megabytes (default: 25) - + Встановити розмір кешу бази даних в мегабайтах (типово: 25) - - Set database disk log size in megabytes (default: 100) - + + Listen for connections on <port> (default: 47950 or testnet: 17950) + Чекати на з'єднання на <port> (типово: 47950 або тестова мережа: 17950) - - Specify connection timeout (in milliseconds) - Вкажіть таймаут з’єднання (в мілісекундах) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - Чекати на з'єднання на порту (по замовченню 8333 або тестова мережа 18333) - - - + Maintain at most <n> connections to peers (default: 125) - Підтримувати не більше <n> зв'язків з колегами (за замовчуванням: 125) + Підтримувати не більше <n> зв'язків з колегами (типово: 125) - - Connect only to the specified node - Підключитись лише до вказаного вузла - - - - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address - - Only connect to nodes in network <net> (IPv4 or IPv6) - - - - - Try to discover public IP address (default: 1) - - - - - Bind to given address. Use [host]:port notation for IPv6 - - - - + Threshold for disconnecting misbehaving peers (default: 100) - Поріг відключення неправильно підєднаних пірів (за замовчуванням: 100) + Поріг відключення неправильно під'єднаних пірів (типово: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - Максимальній розмір вхідного буферу на одне з'єднання (за замовчуванням 86400) + Максимальній розмір вхідного буферу на одне з'єднання (типово: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Максимальоий буфер , <n> * 1000 байт (за умовчанням: 10000) - - - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Максимальній розмір виіхідного буферу на одне з'єднання (за замовчуванням 10000) - - - - Detach block and address databases. Increases shutdown time (default: 0) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + Прослуховувати <port> для JSON-RPC-з'єднань (типово: 47970 або тестова мережа: 17970) + + + Accept command line and JSON-RPC commands - Приймати команди із командного рядка та команди JSON-RPC - + Приймати команди із командного рядка та команди JSON-RPC - + Run in the background as a daemon and accept commands - Запустити в фоновому режимі (як демон) та приймати команди - + Запустити в фоновому режимі (як демон) та приймати команди - + Use the test network - Використовувати тестову мережу - + Використовувати тестову мережу - - Output extra debugging information - Виводити більше налагоджувальної інформації - - - - Prepend debug output with timestamp - Доповнювати налагоджувальний вивід відміткою часу - - - - Send trace/debug info to console instead of debug.log file - Відсилаті налагоджувальну інформацію на консоль, а не у файл debug.log - - - - Send trace/debug info to debugger - Відсилаті налагоджувальну інформацію до налагоджувача - - - - Username for JSON-RPC connections - Ім’я користувача для JSON-RPC-з’єднань - - - - - Password for JSON-RPC connections - Пароль для JSON-RPC-з’єднань - - - - - Listen for JSON-RPC connections on <port> (default: 8332) - Прослуховувати <port> для JSON-RPC-з’єднань (за промовчуванням: 8332) - - - - - Allow JSON-RPC connections from specified IP address - Дозволити JSON-RPC-з’єднання з вказаної IP-адреси - - - - - Send commands to node running on <ip> (default: 127.0.0.1) - Відправляти команди на вузол, запущений на <ip> (за промовчуванням: 127.0.0.1) - - - - - Execute command when the best block changes (%s in cmd is replaced by block hash) + + Accept connections from outside (default: 1 if no -proxy or -connect) - - Upgrade wallet to latest format - - - - - Set key pool size to <n> (default: 100) - Встановити розмір пулу ключів <n> (за промовчуванням: 100) - - - - - Rescan the block chain for missing wallet transactions - Пересканувати ланцюжок блоків, в пошуку втрачених переказів - - - - - How many blocks to check at startup (default: 2500, 0 = all) - - - - - How thorough the block verification is (0-6, default: 1) - - - - - Imports blocks from external blk000?.dat file - - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -Параметри SSL: (див. Bitcoin Wiki) - - - - - Use OpenSSL (https) for JSON-RPC connections - Використовувати OpenSSL (https) для JSON-RPC-з’єднань - - - - - Server certificate file (default: server.cert) - Сертифікату сервера (за промовчуванням: server.cert) - - - - - Server private key (default: server.pem) - Закритий ключ сервера (за промовчуванням: server.pem) - - - - - Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - Допустимі шифри (за промовчуванням: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - - - - Warning: Disk space is low - - - - - This help message - Дана довідка - - - - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - Неможливо встановити блокування на робочий каталог %s. Можливо, гаманець вже запущено. - - - - Bitcoin - Bitcoin - - - - Unable to bind to %s on this computer (bind returned error %d, %s) - - - - - Connect through socks proxy - - - - - Select the version of socks proxy to use (4 or 5, 5 is default) - - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - - - - - Allow DNS lookups for -addnode, -seednode and -connect - - - - - Pass DNS requests to (SOCKS5) proxy - - - - - Loading addresses... - Завантаження адрес... - - - - Error loading blkindex.dat - Помилка при завантаженні blkindex.dat - - - - Error loading wallet.dat: Wallet corrupted - Помилка при завантаженні wallet.dat: Гаманець пошкоджено - - - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - Помилка при завантаженні wallet.dat: Гаманець потребує новішої версії Біткоін-клієнта - - - - Wallet needed to be rewritten: restart Bitcoin to complete - Потрібно перезаписати гаманець: перезапустіть Біткоін-клієнт для завершення - - - - Error loading wallet.dat - Помилка при завантаженні wallet.dat - - - - Invalid -proxy address: '%s' - - - - - Unknown network specified in -noproxy: '%s' - - - - - Unknown network specified in -onlynet: '%s' - - - - - Unknown -socks proxy version requested: %i - - - - - Cannot resolve -bind address: '%s' - - - - - Not listening on any port - - - - - Cannot resolve -externalip address: '%s' - - - - - Invalid amount for -paytxfee=<amount>: '%s' - - - - - Error: could not start node - - - - - Error: Wallet locked, unable to create transaction - - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - - - - - Error: Transaction creation failed - Помилка: не вдалося створити переказ - - - - Sending... - Відправлення... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Помилка: переказ було відхилено. Це може статись, якщо декілька монет з вашого гаманця вже використані, наприклад, якщо ви використовуєте одну копію гаманця (wallet.dat), а монети були використані з іншої копії, але не позначені як використані в цій. - - - - Invalid amount - - - - - Insufficient funds - Недостатньо коштів - - - - Loading block index... - Завантаження індексу блоків... - - - - Add a node to connect to and attempt to keep the connection open - - - - - Unable to bind to %s on this computer. Bitcoin is probably already running. - - - - - Find peers using internet relay chat (default: 0) - - - - - Accept connections from outside (default: 1) - - - - - Find peers using DNS lookup (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 1) - - - - - Use Universal Plug and Play to map the listening port (default: 0) - - - - - Fee per KB to add to transactions you send - Комісія за Кб - - - - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - - - - - Loading wallet... - Завантаження гаманця... - - - - Cannot downgrade wallet - - - - - Cannot initialize keypool - - - - - Cannot write default address - - - - - Rescanning... - Сканування... - - - - Done loading - Завантаження завершене - - - - To use the %s option - - - - + %s, you must set a rpcpassword in the configuration file: - %s +%s It is recommended you use the following random password: -rpcuser=bitcoinrpc +rpcuser=casinocoinrpc rpcpassword=%s (you do not need to remember this password) +The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com - + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Помилка: транзакцію було відхилено. Це може статись, якщо декілька монет з вашого гаманця вже використані, наприклад, якщо ви використовуєте одну копію гаманця (wallet.dat), а монети були використані з іншої копії, але не позначені як використані в цій. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Увага: встановлено занадто велику комісію (-paytxfee). Комісія зніматиметься кожен раз коли ви проводитимете транзакції. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + Увага: будь ласка, перевірте дату і час на своєму комп'ютері. Якщо ваш годинник йде неправильно, CasinoCoin може працювати некоректно. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Увага: помилка читання wallet.dat! Всі ключі прочитано коректно, але дані транзакцій чи записи адресної книги можуть бути пропущені, або пошкоджені. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Увага: файл wallet.dat пошкоджено, дані врятовано! Оригінальний wallet.dat збережено як wallet.{timestamp}.bak до %s; якщо Ваш баланс чи транзакції неправильні, Ви можете відновити їх з резервної копії. + + + + Attempt to recover private keys from a corrupt wallet.dat + Спроба відновити закриті ключі з пошкодженого wallet.dat + + + + Block creation options: + + + + + Connect only to the specified node(s) + Підключитись лише до вказаного вузла + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + Помилка ініціалізації бази даних блоків + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + Помилка завантаження бази даних блоків + + + + Error opening block database + + + + + Error: Disk space is low! + Помилка: Мало вільного місця на диску! + + + + Error: Wallet locked, unable to create transaction! + Помилка: Гаманець заблокований, неможливо створити транзакцію! + + + + Error: system error: + Помилка: системна помилка: + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + Скільки блоків перевіряти під час запуску (типово: 288, 0 = всі) + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + Імпорт блоків з зовнішнього файлу blk000??.dat + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Інформація + + + + Invalid -tor address: '%s' + Помилка в адресі -tor: «%s» + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Максимальний буфер, <n>*1000 байт (типово: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Максимальній розмір вихідного буферу на одне з'єднання, <n>*1000 байт (типово: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + Виводити більше налагоджувальної інформації. Мається на увазі всі шнші -debug* параметри + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + Доповнювати налагоджувальний вивід відміткою часу + + + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + Параметри SSL: (див. CasinoCoin Wiki для налаштування SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Вибір версії socks-проксі для використання (4-5, типово: 5) + + + + Send trace/debug info to console instead of debug.log file + Відсилати налагоджувальну інформацію на консоль, а не у файл debug.log + + + + Send trace/debug info to debugger + Відсилати налагоджувальну інформацію до налагоджувача + + + + Set maximum block size in bytes (default: 250000) + Встановити максимальний розмір блоку у байтах (типово: 250000) + + + + Set minimum block size in bytes (default: 0) + Встановити мінімальний розмір блоку у байтах (типово: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Стискати файл debug.log під час старту клієнта (типово: 1 коли відсутутній параметр -debug) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + Вказати тайм-аут підключення у мілісекундах (типово: 5000) + + + + System error: + Системна помилка: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + Намагатись використовувати UPnP для відображення порту, що прослуховується на роутері (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Намагатись використовувати UPnP для відображення порту, що прослуховується на роутері (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + Ім'я користувача для JSON-RPC-з'єднань + + + + Warning + Попередження + + + + Warning: This version is obsolete, upgrade required! + Увага: Поточна версія застаріла, необхідне оновлення! + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + wallet.dat пошкоджено, відновлення не вдалося + + + + Password for JSON-RPC connections + Пароль для JSON-RPC-з'єднань + + + + Allow JSON-RPC connections from specified IP address + Дозволити JSON-RPC-з'єднання з вказаної IP-адреси + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Відправляти команди на вузол, запущений на <ip> (типово: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + Модернізувати гаманець до останнього формату + + + + Set key pool size to <n> (default: 100) + Встановити розмір пулу ключів <n> (типово: 100) + + + + Rescan the block chain for missing wallet transactions + Пересканувати ланцюжок блоків, в пошуку втрачених транзакцій + + + + Use OpenSSL (https) for JSON-RPC connections + Використовувати OpenSSL (https) для JSON-RPC-з'єднань + + + + Server certificate file (default: server.cert) + Файл сертифіката сервера (типово: server.cert) + + + + Server private key (default: server.pem) + Закритий ключ сервера (типово: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Допустимі шифри (типово: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Дана довідка + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Неможливо прив'язати до порту %s на цьому комп'ютері (bind returned error %d, %s) + + + + Connect through socks proxy + Підключитись через SOCKS-проксі + + + + Allow DNS lookups for -addnode, -seednode and -connect + Дозволити пошук в DNS для команд -addnode, -seednode та -connect + + + + Loading addresses... + Завантаження адрес... + + + + Error loading wallet.dat: Wallet corrupted + Помилка при завантаженні wallet.dat: Гаманець пошкоджено + + + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + Помилка при завантаженні wallet.dat: Гаманець потребує новішої версії Біткоін-клієнта + + + + Wallet needed to be rewritten: restart CasinoCoin to complete + Потрібно перезаписати гаманець: перезапустіть Біткоін-клієнт для завершення + + + + Error loading wallet.dat + Помилка при завантаженні wallet.dat + + + + Invalid -proxy address: '%s' + Помилка в адресі проксі-сервера: «%s» + + + + Unknown network specified in -onlynet: '%s' + Невідома мережа вказана в -onlynet: «%s» + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + Помилка у величині комісії -paytxfee=<amount>: «%s» + + + + Invalid amount + Некоректна кількість + + + + Insufficient funds + Недостатньо коштів + + + + Loading block index... + Завантаження індексу блоків... + + + + Add a node to connect to and attempt to keep the connection open + Додати вузол до підключення і лишити його відкритим + + + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + Неможливо прив'язати до порту %s на цьому комп'ютері. Можливо гаманець вже запущено. + + + + Fee per KB to add to transactions you send + Комісія за КБ + + + + Loading wallet... + Завантаження гаманця... + + + + Cannot downgrade wallet + + + + + Cannot write default address + Неможливо записати типову адресу + + + + Rescanning... + Сканування... + + + + Done loading + Завантаження завершене + + + + To use the %s option + + + + Error - + Помилка - - An error occured while setting up the RPC port %i for listening: %s - - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - Увага: будь ласка, перевірте дату і час на свому комп’ютері. Якщо ваш годинник йде неправильно, Bitcoin може працювати некоректно. + Ви мусите встановити rpcpassword=<password> в файлі конфігурації: +%s +Якщо файл не існує, створіть його із правами тільки для читання власником (owner-readable-only). \ No newline at end of file diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 087e19b..d083aea 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - 关于比特币 + + About CasinoCoin + 关于莱特币 - - <b>Bitcoin</b> version - <b>比特币</b>版本 + + <b>CasinoCoin</b> version + <b>莱特币</b>版本 - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - 版权归比特币开发者所有 © 2009-2012 + +This is experimental software. -这是一个实验性软件。 - -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + Copyright + 版权 + + + + The CasinoCoin developers + CasinoCoin-qt 客户端开发团队 + AddressBookPage - + Address Book - 地址薄 + 通讯录 - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - 这些是你接受支付的比特币地址。当支付时你可以给出不同的地址,以便追踪不同的支付者。 - - - + Double-click to edit address or label 双击以编辑地址或标签 - + Create a new address 创建新地址 - + Copy the currently selected address to the system clipboard 复制当前选中地址到系统剪贴板 - + &New Address &新建地址 - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + 这是您用来收款的莱特币地址。为了标记不同的资金来源,建议为每个付款人保留不同的收款地址。 + + + &Copy Address &复制地址 - + Show &QR Code 显示二维码 - - Sign a message to prove you own this address - 发送签名消息以证明您是该比特币地址的拥有者 + + Sign a message to prove you own a CasinoCoin address + 签名消息,证明这个地址属于您。 - - &Sign Message - &发送签名消息 + + Sign &Message + 对消息签名 - - Delete the currently selected address from the list. Only sending addresses can be deleted. - 从列表中删除当前选中地址。只有发送地址可以被删除。 + + Delete the currently selected address from the list + 从列表中删除选中的地址 - + + Export the data in the current tab to a file + 导出当前数据到文件 + + + + &Export + &导出 + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + 验证消息,确保消息是由指定的莱特币地址签名过的。 + + + + &Verify Message + &验证消息 + + + &Delete &删除 - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 这是您用来付款的莱特币地址。在付款前,请总是核实付款金额和收款地址。 + + + Copy &Label 复制 &标签 - + &Edit &编辑 - - Export Address Book Data - 导出地址薄数据 + + Send &Coins + 付款 - + + Export Address Book Data + 导出通讯录数据 + + + Comma separated file (*.csv) 逗号分隔文件 (*.csv) - + Error exporting 导出错误 - + Could not write to file %1. 无法写入文件 %1。 @@ -126,17 +164,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label 标签 - + Address 地址 - + (no label) (没有标签) @@ -144,432 +182,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog 密码对话框 - + Enter passphrase - 输入口令 + 输入密码 - + New passphrase - 新口令 + 新密码 - + Repeat new passphrase - 重复新口令 + 重复新密码 - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - 输入钱包的新口令。<br/>使用的口令请至少包含<b>10个以上随机字符</>,或者是<b>8个以上的单词</b>。 + 输入钱包的新密码。<br/>使用的密码请至少包含<b>10个以上随机字符</>,或者是<b>8个以上的单词</b>。 - + Encrypt wallet 加密钱包 - + This operation needs your wallet passphrase to unlock the wallet. - 该操作需要您首先使用口令解锁钱包。 + 该操作需要您首先使用密码解锁钱包。 - + Unlock wallet 解锁钱包 - + This operation needs your wallet passphrase to decrypt the wallet. - 该操作需要您首先使用口令解密钱包。 + 该操作需要您首先使用密码解密钱包。 - + Decrypt wallet 解密钱包 - + Change passphrase - 修改口令 + 修改密码 - + Enter the old and new passphrase to the wallet. - 请输入钱包的旧口令与新口令。 + 请输入钱包的旧密码与新密码。 - + Confirm wallet encryption 确认加密钱包 - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - 警告:如果您加密了您的钱包之后忘记了口令,您将会<b>失去所有的比特币</b>! -确定要加密钱包吗? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + 警告:如果您加密了您的钱包,但是忘记了密码,你将会<b>丢失所有的莱特币</b>! - - + + Are you sure you wish to encrypt your wallet? + 您确定需要为钱包加密吗? + + + + 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. + 重要提示:您以前备份的钱包文件应该替换成最新生成的加密钱包文件(重新备份)。从安全性上考虑,您以前备份的未加密的钱包文件,在您使用新的加密钱包后将无效,请重新备份。 + + + + + Warning: The Caps Lock key is on! + 警告:大写锁定键处于打开状态! + + + + Wallet encrypted 钱包已加密 - - Bitcoin 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. - 将关闭软件以完成加密过程。 请您谨记:钱包加密并不是万能的,电脑中毒,您的比特币还是有可能丢失。 + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + 将关闭软件以完成加密过程。 请您谨记:钱包加密并不是万能的,电脑中毒,您的莱特币还是有可能丢失。 - - - Warning: The Caps Lock key is on. - 警告:大写锁定键CapsLock开启 - - - - - - + + + + Wallet encryption failed 钱包加密失败 - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. 由于一个本地错误,加密钱包操作已经失败。您的钱包没有被加密。 - - + + The supplied passphrases do not match. - 口令不匹配。 + 密码不匹配。 - + Wallet unlock failed 钱包解锁失败 - - - + + + The passphrase entered for the wallet decryption was incorrect. - 用于解密钱包的口令不正确。 + 用于解密钱包的密码不正确。 - + Wallet decryption failed 钱包解密失败。 - - Wallet passphrase was succesfully changed. - 钱包口令修改成功 + + Wallet passphrase was successfully changed. + 修改钱包密码成功。 BitcoinGUI - - Bitcoin Wallet - 比特币钱包 - - - + Sign &message... 对&消息签名... - - Show/Hide &Bitcoin - 显示/隐藏 比特币客户端 - - - + Synchronizing with network... 正在与网络同步... - + &Overview &概况 - + Show general overview of wallet 显示钱包概况 - + &Transactions - &交易 + &交易记录 - + Browse transaction history 查看交易历史 - - &Address Book - &地址薄 - - - + Edit the list of stored addresses and labels 修改存储的地址和标签列表 - - &Receive coins - &接收货币 - - - + Show the list of addresses for receiving payments 显示接收支付的地址列表 - - &Send coins - &发送货币 - - - - Prove you control an address - 证明您拥有某个比特币地址 - - - + E&xit 退出 - + Quit application 退出程序 - - &About %1 - &关于 %1 + + Show information about CasinoCoin + 显示莱特币的相关信息 - - Show information about Bitcoin - 显示比特币的相关信息 - - - + About &Qt 关于 &Qt - + Show information about Qt 显示Qt相关信息 - + &Options... &选项... - + &Encrypt Wallet... &加密钱包... - + &Backup Wallet... &备份钱包... - + &Change Passphrase... &修改密码... - - - ~%n block(s) remaining - ~还剩 %n 个区块 + + + Importing blocks from disk... + 正在从磁盘导入数据块... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - 已下载 %2 个交易历史区块中的 %1 个 (完成率 %3% ). + + Reindexing blocks on disk... + 正在为数据块建立索引... - - &Export... - &导出... + + Send coins to a CasinoCoin address + 向一个莱特币地址发送莱特币 - - Send coins to a Bitcoin address - 向一个比特币地址发送比特币 - - - - Modify configuration options for Bitcoin + + Modify configuration options for CasinoCoin 设置选项 - - Show or hide the Bitcoin window - 显示或隐藏比特币客户端窗口 - - - - Export the data in the current tab to a file - 导出当前数据到文件 - - - - Encrypt or decrypt wallet - 加密或解密钱包 - - - + Backup wallet to another location 备份钱包到其它文件夹 - + Change the passphrase used for wallet encryption 修改钱包加密口令 - + &Debug window &调试窗口 - + Open debugging and diagnostic console 在诊断控制台调试 - + &Verify message... &验证消息... - - Verify a message signature - 验证签名消息 + + + CasinoCoin + 莱特币 - + + Wallet + 钱包 + + + + &Send + &发送 + + + + &Receive + &接收 + + + + &Addresses + &地址 + + + + &About CasinoCoin + &关于莱特币 + + + + &Show / Hide + &显示 / 隐藏 + + + + Show or hide the main Window + 显示或隐藏主窗口 + + + + Encrypt the private keys that belong to your wallet + 对钱包中的私钥加密 + + + + Sign messages with your CasinoCoin addresses to prove you own them + 用莱特币地址关联的私钥为消息签名,以证明您拥有这个莱特币地址 + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + 校验消息,确保该消息是由指定的莱特币地址所有者签名的 + + + &File &文件 - + &Settings &设置 - + &Help &帮助 - + Tabs toolbar 分页工具栏 - - Actions toolbar - 动作工具栏 - - - - + + [testnet] [testnet] - - - Bitcoin client - 比特币客户端 + + CasinoCoin client + 莱特币客户端 - - %n active connection(s) to Bitcoin network - %n 个到比特币网络的活动连接 + + %n active connection(s) to CasinoCoin network + 到莱特币网络的连接共有%n条 - - Downloaded %1 blocks of transaction history. - %1 个交易历史的区块已下载 + + No block source available... + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. + %1 / %2 个交易历史的区块已下载 + + + + Processed %1 blocks of transaction history. + 已处理 %1 个交易历史数据块。 - - %n second(s) ago - %n 秒前 - - - - %n minute(s) ago - %n 分种前 - - - - %n hour(s) ago + + %n hour(s) %n 小时前 - - %n day(s) ago + + %n day(s) %n 天前 + + + %n week(s) + %n 周前 + - + + %1 behind + 落后 %1 + + + + Last received block was generated %1 ago. + 最新收到的区块产生于 %1。 + + + + Transactions after this will not yet be visible. + 在此之后的交易尚未可见 + + + + Error + 错误 + + + + Warning + 警告 + + + + Information + 信息 + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + 该交易的字节数超标。您可以选择支付%1的交易费给处理您的交易的网络节点,有助于莱特币网络的运行。您愿意支付这笔交易费用吗? + + + Up to date 最新状态 - + Catching up... 更新中... - - Last received block was generated %1. - 最新收到的区块产生于 %1。 - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - 该笔交易的数据量超限.您可以选择支付 %1 交易费, 交易费将支付给处理该笔交易的网络节点,有助于维持比特币网络的运行. 您愿意支付交易费用吗? - - - + Confirm transaction fee 确认交易费 - + Sent transaction 已发送交易 - + Incoming transaction 流入交易 - + Date: %1 Amount: %2 Type: %3 @@ -582,539 +648,486 @@ Address: %4 - + + + URI handling + URI 处理 + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + URI无法解析!原因可能是莱特币地址不正确,或者URI参数错误。 + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> 钱包已被<b>加密</b>,当前为<b>解锁</b>状态 - + Wallet is <b>encrypted</b> and currently <b>locked</b> 钱包已被<b>加密</b>,当前为<b>锁定</b>状态 - - Backup Wallet - 备份钱包 - - - - Wallet Data (*.dat) - 钱包文件(*.dat) - - - - Backup Failed - 备份失败 - - - - There was an error trying to save the wallet data to the new location. - 备份钱包到其它文件夹失败. - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - 发生致命错误. 比特币客户端的安全存在问题,将退出. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + 发生严重错误。 ClientModel - + Network Alert 网络警报 - - DisplayOptionsPage - - - Display - 查看 - - - - default - 缺省 - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - 设置语言选项。需重启客户端软件才能生效。 - - - - User Interface &Language: - &语言: - - - - &Unit to show amounts in: - &比特币金额单位: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - 选择显示及发送比特币时使用的最小单位 - - - - &Display addresses in transaction list - 在交易清单中&显示比特币地址 - - - - Whether to show Bitcoin addresses in the transaction list - 是否在交易清单中显示比特币地址 - - - - Warning - 警告 - - - - This setting will take effect after restarting Bitcoin. - 需要重启客户端软件才能生效。 - - EditAddressDialog - + Edit Address 编辑地址 - + &Label &标签 - + The label associated with this address book entry 与此地址条目关联的标签 - + &Address &地址 - + The address associated with this address book entry. This can only be modified for sending addresses. 该地址与地址簿中的条目已关联,无法作为发送地址编辑。 - + New receiving address 新接收地址 - + New sending address 新发送地址 - + Edit receiving address 编辑接收地址 - + Edit sending address 编辑发送地址 - + The entered address "%1" is already in the address book. - 输入的地址 "%1" 已经存在于地址薄。 + 输入的地址 "%1" 已经存在于地址簿。 - - The entered address "%1" is not a valid Bitcoin address. - 您输入的 "%1" 不是合法的比特币地址. + + The entered address "%1" is not a valid CasinoCoin address. + 您输入的 "%1" 不是合法的莱特币地址. - + Could not unlock wallet. 无法解锁钱包 - + New key generation failed. 密钥创建失败. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - Bitcoin-Qt + + + CasinoCoin-Qt + CasinoCoin-Qt - + version 版本 - + Usage: 使用: - - options - 选项 + + command-line options + 命令行选项 - + UI options UI选项 - + Set language, for example "de_DE" (default: system locale) 设置语言, 例如 "de_DE" (缺省: 系统语言) - + Start minimized 启动时最小化 - + Show splash screen on startup (default: 1) 启动时显示版权页 (缺省: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - 关闭时分开区块数据库和地址数据库. 这意味着您可以将数据库文件移动至其他文件夹. 钱包文件始终是分开的. + + Options + 选项 - + + &Main + &主要的 + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + Pay transaction &fee 支付交易 &费用 - - Main - 主选项 + + Automatically start CasinoCoin after logging in to the system. + 登录系统后自动开启莱特币客户端 - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - 建议支付交易费用,有助于您的交易得到尽快处理. 绝大多数交易的字节数为 1 kB. 建议支付0.01个比特币. - - - - &Start Bitcoin on system login + + &Start CasinoCoin on system login 启动时&运行 - - Automatically start Bitcoin after logging in to the system - 系统启动后自动运行比特币客户端软件 + + Reset all client options to default. + 恢复客户端的缺省设置 - - &Detach databases at shutdown - &关闭客户端时分离数据库 - - - - MessagePage - - - Sign Message - 对消息签名 + + &Reset Options + 恢复缺省设置 - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - 您可以用你的地址对消息进行签名,以证明您是该地址的所有人。注意不要对模棱两可的消息签名,以免遭受钓鱼式攻击。请确保消息真实明确的表达了您的意愿。 + + &Network + &网络 - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 用来签名的比特币地址 (例如 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + 自动在路由器中打开莱特币端口。只有当您的路由器开启 UPnP 选项时此功能才有效。 - - Choose adress from address book - 从地址簿选择地址 - - - - Alt+A - Alt+A - - - - Paste address from clipboard - 从剪贴板粘贴地址 - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - 请输入您要发送的签名消息 - - - - Copy the current signature to the system clipboard - 复制当前签名至剪切板 - - - - &Copy Signature - &复制签名 - - - - Reset all sign message fields - 清空所有签名消息栏 - - - - Clear &All - 清除 &所有 - - - - Click "Sign Message" to get signature - 单击“发送签名消息"获取签名 - - - - Sign a message to prove you own this address - 发送签名消息以证明您是该比特币地址的拥有者 - - - - &Sign Message - &发送签名消息 - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 请输入比特币地址 (例如: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - 签名错误 - - - - %1 is not a valid address. - %1 不是合法的比特币地址。 - - - - %1 does not refer to a key. - %1 找不到相关的钥匙. - - - - Private key for %1 is not available. - %1 的秘钥不可用。 - - - - Sign failed - 签名失败 - - - - NetworkOptionsPage - - - Network - 网络 - - - + Map port using &UPnP 使用 &UPnP 映射端口 - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - 自动在路由器中打开比特币端口。只有当您的路由器开启 UPnP 选项时此功能才有效。 + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + 通过代理服务器连接莱特币网络(例如:通过Tor连接) - - &Connect through SOCKS4 proxy: - &通过SOCKS4代理连接 + + &Connect through SOCKS proxy: + &通过Socks代理连接: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - 通过一个SOCKS4代理连接到比特币网络 (如使用Tor连接时) - - - + Proxy &IP: 代理服务器&IP: - - &Port: - &端口: - - - + IP address of the proxy (e.g. 127.0.0.1) 代理服务器IP (如 127.0.0.1) - - Port of the proxy (e.g. 1234) - 代理端口 (比如 1234) + + &Port: + &端口: - - - OptionsDialog - - Options - 选项 + + Port of the proxy (e.g. 9050) + 代理端口(例如 9050) + + + + SOCKS &Version: + Socks &版本 + + + + SOCKS version of the proxy (e.g. 5) + Socks代理版本 (例如 5) + + + + &Window + &窗口 + + + + Show only a tray icon after minimizing the window. + 最小化窗口后仅显示托盘图标 + + + + &Minimize to the tray instead of the taskbar + &最小化到托盘 + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + 当窗口关闭时程序最小化而不是退出。当使用该选项时,程序只能通过在菜单中选择退出来关闭 + + + + M&inimize on close + 单击关闭按钮最小化 + + + + &Display + &显示 + + + + User Interface &language: + 用户界面&语言: + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + 在这里设置用户界面的语言。设置将在客户端重启后生效。 + + + + &Unit to show amounts in: + &莱特币金额单位: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + 选择莱特币单位。 + + + + Whether to show CasinoCoin addresses in the transaction list or not. + 是否需要在交易清单中显示莱特币地址。 + + + + &Display addresses in transaction list + 在交易清单中&显示莱特币地址 + + + + &OK + &确定 + + + + &Cancel + &取消 + + + + &Apply + &应用 + + + + default + 缺省 + + + + Confirm options reset + 确认恢复缺省设置 + + + + Some settings may require a client restart to take effect. + 某些设置选项需要重启客户端才能生效 + + + + Do you want to proceed? + 您希望继续吗? + + + + + Warning + 警告 + + + + + This setting will take effect after restarting CasinoCoin. + 需要重启客户端软件才能生效。 + + + + The supplied proxy address is invalid. + 提供的代理服务器地址无效。 OverviewPage - + Form 表单 - - - 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. - 现在显示的消息可能是过期的. 在连接上比特币网络节点后,您的钱包将自动与网络同步,但是这个过程还没有完成. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + 现在显示的消息可能是过期的. 在连接上莱特币网络节点后,您的钱包将自动与网络同步,但是这个过程还没有完成. - + Balance: - 余额 + 余额: - - Number of transactions: - 交易笔数 - - - + Unconfirmed: 未确认: - + Wallet 钱包 - - <b>Recent transactions</b> - <b>当前交易</b> + + Immature: + 未成熟的: - + + Mined balance that has not yet matured + 尚未成熟的挖矿收入余额 + + + + <b>Recent transactions</b> + <b>最近交易记录</b> + + + Your current balance 您的当前余额 - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance 尚未确认的交易总额, 未计入当前余额 - - Total number of transactions in wallet - 钱包总交易数量 - - - - + + out of sync - 来自同步过程 + 数据同步中 + + + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + 暂时无法启动莱特币:点击支付功能 QRCodeDialog - + QR Code Dialog 二维码对话框 - - QR Code - 二维码 - - - + Request Payment 请求付款 - + Amount: 金额: - - BTC - BTC - - - + Label: 标签: - + Message: 消息: - + &Save As... &另存为 - + Error encoding URI into QR Code. 将 URI 转换成二维码失败. - + + The entered amount is invalid, please check. + 输入的金额非法,请检查。 + + + Resulting URI too long, try to reduce the text for label / message. URI 太长, 请试着精简标签/消息的内容. - + Save QR Code 保存二维码 - + PNG Images (*.png) PNG图像文件(*.png) @@ -1122,125 +1135,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - 调试窗口 - - - + Client name 客户端名称 - - - - - - - - - + + + + + + + + + + N/A 不可用 - + Client version 客户端版本 - + &Information &信息 - - Client - 客户端 + + Using OpenSSL version + 使用OpenSSL版本 - + Startup time 启动时间 - + Network 网络 - + Number of connections 连接数 - + On testnet - 当前为比特币测试网络 + 当前为莱特币测试网络 - + Block chain - 区块链 + 数据链 - + Current number of blocks - 当前区块数 + 当前数据块数量 - + Estimated total blocks - 预计区块数 + 预计数据块数量 - + Last block time - 上一区块时间 + 上一数据块时间 - - Debug logfile - 调试日志文件 - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - 在当前数据目录打开调试日志文件. 大文件,需要等待几秒. - - - + &Open &打开 - + + Command-line options + 命令行选项 + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + 显示CasinoCoin命令行选项帮助信息 + + + + &Show + &显示 + + + &Console &控制台 - + Build date 创建时间 - + + CasinoCoin - Debug window + 莱特币 - 调试窗口 + + + + CasinoCoin Core + 莱特币核心 + + + + Debug log file + 调试日志文件 + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + 打开当前目录中的调试日志文件。日志文件大的话可能要等上几秒钟。 + + + Clear console 清空控制台 - - Welcome to the Bitcoin RPC console. + + Welcome to the CasinoCoin RPC console. 欢迎来到 RPC 控制台. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. 使用上下方向键浏览历史, <b>Ctrl-L</b>清除屏幕. - + Type <b>help</b> for an overview of available commands. 使用 <b>help</b> 命令显示帮助信息. @@ -1248,1289 +1282,1673 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins 发送货币 - + Send to multiple recipients at once 一次发送给多个接收者 - - &Add Recipient - &添加接收人 + + Add &Recipient + 添加收款人 - + Remove all transaction fields 移除所有交易项 - + Clear &All 清除 &所有 - + Balance: - 余额 + 余额: - + 123.456 BTC 123.456 BTC - + Confirm the send action 确认并发送货币 - - &Send - &发送 + + S&end + 发送 - + <b>%1</b> to %2 (%3) <b>%1</b> 到 %2 (%3) - + Confirm send coins 确认发送货币 - + Are you sure you want to send %1? 确定您要发送 %1? - + and - - The recepient address is not valid, please recheck. - 接收者地址不合法,请检查。 + + The recipient address is not valid, please recheck. + 收款人地址不合法,请检查。 - + The amount to pay must be larger than 0. 支付金额必须大于0. - + The amount exceeds your balance. - 金额超出您的账上余额 + 金额超出您的账上余额。 - + The total exceeds your balance when the %1 transaction fee is included. - 计入 %1 交易费后的金额超出您的账上余额. + 计入 %1 交易费后的金额超出您的账上余额。 - + Duplicate address found, can only send to each address once per send operation. 发现重复的地址, 每次只能对同一地址发送一次. - - Error: Transaction creation failed. - 错误: 创建交易失败. + + Error: Transaction creation failed! + 错误:创建交易失败! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - 错误: 交易被拒绝. 如果您使用的是备份钱包,可能存在两个钱包不同步的情况,另一个钱包中的比特币已经被使用,但本地的这个钱包尚没有记录。 + 错误: 交易被拒绝. 如果您使用的是备份钱包,可能存在两个钱包不同步的情况,另一个钱包中的莱特币已经被使用,但本地的这个钱包尚没有记录。 SendCoinsEntry - + Form 表单 - + A&mount: 金额 - + Pay &To: - 支付 &到: + 付款&给: - - + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 付款给这个地址 (例如 Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Enter a label for this address to add it to your address book 为这个地址输入一个标签,以便将它添加到您的地址簿 - + &Label: &标签: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 付款地址 (例如: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book - 从地址薄选择地址 + 从地址簿选择地址 - + Alt+A Alt+A - + Paste address from clipboard 从剪贴板粘贴地址 - + Alt+P Alt+P - + Remove this recipient 移除此接收者 - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 请输入比特币地址 (例如: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 请输入莱特币地址 (例如: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + 签名 - 为消息签名/验证签名消息 + + + + &Sign Message + &签名消息 + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + 您可以用你的地址对消息进行签名,以证明您是该地址的所有人。注意不要对模棱两可的消息签名,以免遭受钓鱼式攻击。请确保消息内容准确的表达了您的真实意愿。 + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 用于签名消息的地址(例如: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + 从地址簿选择地址 + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + 从剪贴板粘贴地址 + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + 请输入您要发送的签名消息 + + + + Signature + 签名 + + + + Copy the current signature to the system clipboard + 复制当前签名至剪切板 + + + + Sign the message to prove you own this CasinoCoin address + 签名消息,证明这个地址属于您。 + + + + Sign &Message + 消息签名 + + + + Reset all sign message fields + 清空所有签名消息栏 + + + + + Clear &All + 清除 &所有 + + + + &Verify Message + &验证消息 + + + + Enter the signing 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. + 在下面输入签名地址,消息(请确保换行符、空格符、制表符等等一个不漏)和签名以验证消息。请确保签名信息准确,提防中间人攻击。 + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 用于签名消息的地址(例如: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + 验证消息,确保消息是由指定的莱特币地址签名过的。 + + + + Verify &Message + 验证消息签名 + + + + Reset all verify message fields + 清空所有验证消息栏 + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 请输入莱特币地址 (例如: Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + 单击“签名消息“产生签名。 + + + + Enter CasinoCoin signature + 输入莱特币签名 + + + + + The entered address is invalid. + 输入的地址非法。 + + + + + + + Please check the address and try again. + 请检查地址后重试。 + + + + + The entered address does not refer to a key. + 输入的地址没有关联的公私钥对。 + + + + Wallet unlock was cancelled. + 钱包解锁动作取消。 + + + + Private key for the entered address is not available. + 找不到输入地址关联的私钥。 + + + + Message signing failed. + 消息签名失败。 + + + + Message signed. + 消息已签名。 + + + + The signature could not be decoded. + 签名无法解码。 + + + + + Please check the signature and try again. + 请检查签名后重试。 + + + + The signature did not match the message digest. + 签名与消息摘要不匹配。 + + + + Message verification failed. + 消息验证失败。 + + + + Message verified. + 消息验证成功。 + + + + SplashScreen + + + The CasinoCoin developers + CasinoCoin-qt 客户端开发团队 + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - 开启 %1 个数据块 - - - + Open until %1 至 %1 个数据块时开启 - - %1/offline? - %1/离线? + + %1/offline + %1 / 离线 - + %1/unconfirmed %1/未确认 - + %1 confirmations %1 确认项 - - <b>Status:</b> - <b>状态:</b> + + Status + 状态 + + + + , broadcast through %n node(s) + 通过 %n 个节点广播 - - , has not been successfully broadcast yet - , 未被成功广播 + + Date + 日期 - - , broadcast through %1 node - ,同过 %1 节点广播 + + Source + - - , broadcast through %1 nodes - ,同过 %1 节点组广播 + + Generated + 生成 - - <b>Date:</b> - <b>日期:</b> + + + From + 来自 - - <b>Source:</b> Generated<br> - <b>来源:</b> 生成<br> + + + + To + - - - <b>From:</b> - <b>从:</b> + + + own address + 自己的地址 - - unknown - 未知 + + label + 标签 - - - - <b>To:</b> - <b>到:</b> + + + + + + Credit + 收入 + + + + matures in %n more block(s) + 将在 %n 个数据块后成熟 - - (yours, label: - (您的, 标签: + + not accepted + 未被接受 - - (yours) - (您的) - - - - - - - <b>Credit:</b> - <b>到帐:</b> - - - - (%1 matures in %2 more blocks) - (%1 成熟于 %2 以上数据块) - - - - (not accepted) - (未接受) - - - - - - <b>Debit:</b> + + + + + Debit 支出 - - <b>Transaction fee:</b> + + Transaction fee 交易费 - - <b>Net amount:</b> - <b>网络金额:</b> + + Net amount + 净额 - - Message: - 消息: + + Message + 消息 - - Comment: + + Comment 备注 - - Transaction ID: - 交易ID: + + Transaction ID + 交易ID - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - 新生产的比特币必须等待120个数据块之后才能被使用. 当您生产出此数据块,它将被广播至比特币网络并添加至数据链. 如果添加到数据链失败, 它的状态将变成"不被接受",生产的比特币将不能使用. 在您生产新数据块的几秒钟内, 如果其它节点也生产出同样的数据块,有可能会发生这种情况. + + Generated coins must mature 120 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. + 新挖出的莱特币必须等确120个确认才能使用。您生产出的数据块,将被广播到全网并添加到数据块链。如果入链失败,状态将变为“未被接受”,意味着您的数据块竞争失败,挖出的莱特币将不能使用。当某个节点先于你几秒生产出新的数据块,这种情况会偶尔发生。 + + + + Debug information + 调试信息 + + + + Transaction + 交易 + + + + Inputs + 输入 + + + + Amount + 金额 + + + + true + 正确 + + + + false + 错误 + + + + , has not been successfully broadcast yet + , 未被成功广播 + + + + Open for %n more block(s) + Open for %n more block + + + + unknown + 未知 TransactionDescDialog - + Transaction details - 交易细节 + 交易明细 - + This pane shows a detailed description of the transaction - 当前面板显示了交易的详细描述 + 当前面板显示了交易的详细信息 TransactionTableModel - + Date 日期 - + Type 类型 - + Address 地址 - + Amount 数量 - - Open for %n block(s) - 开启 %n 个数据块 + + Open for %n more block(s) + Open for %n more block - + Open until %1 至 %1 个数据块时开启 - + Offline (%1 confirmations) 离线 (%1 个确认项) - + Unconfirmed (%1 of %2 confirmations) 未确认 (%1 / %2 条确认信息) - + Confirmed (%1 confirmations) 已确认 (%1 条确认信息) - - Mined balance will be available in %n more blocks - 挖矿所得将在 %n 个数据块之后可用 + + Mined balance will be available when it matures in %n more block(s) + 挖矿收入余额将在 %n 个数据块后可用 - + This block was not received by any other nodes and will probably not be accepted! - 此区块未被其他节点接收,并可能不被接受! + 此数据块未被其他节点接收,并可能不被接受! - + Generated but not accepted 已生成但未被接受 - + Received with 接收于 - + Received from 收款来自 - + Sent to 发送到 - + Payment to yourself 付款给自己 - + Mined 挖矿所得 - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. 交易状态。 鼠标移到此区域上可显示确认消息项的数目。 - + Date and time that the transaction was received. - 接收交易的时间 + 接收莱特币的时间 - + Type of transaction. 交易类别。 - + Destination address of transaction. 交易目的地址。 - + Amount removed from or added to balance. - 从余额添加或移除的金额 + 从余额添加或移除的金额。 TransactionView - - + + All 全部 - + Today 今天 - + This week 本周 - + This month 本月 - + Last month 上月 - + This year 今年 - + Range... 范围... - + Received with 接收于 - + Sent to 发送到 - + To yourself 到自己 - + Mined 挖矿所得 - + Other 其他 - + Enter address or label to search 输入地址或标签进行搜索 - + Min amount 最小金额 - + Copy address 复制地址 - + Copy label 复制标签 - + Copy amount 复制金额 - + + Copy transaction ID + 复制交易编号 + + + Edit label 编辑标签 - + Show transaction details 显示交易详情 - + Export Transaction Data 导出交易数据 - + Comma separated file (*.csv) 逗号分隔文件(*.csv) - + Confirmed 已确认 - + Date 日期 - + Type 类别 - + Label 标签 - + Address 地址 - + Amount 金额 - + ID ID - + Error exporting 导出错误 - + Could not write to file %1. 无法写入文件 %1。 - + Range: 范围: - + to - - VerifyMessageDialog - - - Verify Signed Message - 验证签名消息 - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - 请在下面输入消息和签名 (注意不要遗漏换行、空格和缩进符这些看不见的字符) 获取用来签名的比特币地址. - - - - Verify a message and obtain the Bitcoin address used to sign the message - 验证消息并获取用来签名的比特币地址 - - - - &Verify Message - &验证消息 - - - - Copy the currently selected address to the system clipboard - 复制当前选中地址到系统剪贴板 - - - - &Copy Address - &复制地址 - - - - Reset all verify message fields - 清空所有验证消息栏 - - - - Clear &All - 清除 &所有 - - - - Enter Bitcoin signature - 输入比特币签名 - - - - Click "Verify Message" to obtain address - 单击 "验证消息" 获取比特币地址 - - - - - Invalid Signature - 非法签名 - - - - The signature could not be decoded. Please check the signature and try again. - 签名无法解码. 请检查签名后再试一次. - - - - The signature did not match the message digest. Please check the signature and try again. - 签名和消息摘要不吻合.请检查签名后再试一次. - - - - Address not found in address book. - 地址簿中找不到该地址. - - - - Address found in address book: %1 - 地址簿中找不到该地址: %1 - - WalletModel - - Sending... - 发送中... + + Send Coins + 发送莱特币 - WindowOptionsPage + WalletView - - Window - 窗口 + + &Export + - - &Minimize to the tray instead of the taskbar - &最小化到托盘 + + Export the data in the current tab to a file + 导出当前数据到文件 - - Show only a tray icon after minimizing the window - 最小化窗口后只显示一个托盘标志 + + Backup Wallet + 备份钱包 - - M&inimize on close - 单击关闭按钮时&最小化 + + Wallet Data (*.dat) + 钱包文件(*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - 当窗口关闭时程序最小化而不是退出。当使用该选项时,程序只能通过在菜单中选择退出来关闭 + + Backup Failed + 备份失败 + + + + There was an error trying to save the wallet data to the new location. + 备份钱包到其它文件夹失败. + + + + Backup Successful + 备份成功 + + + + The wallet data was successfully saved to the new location. + 钱包数据成功存储到新位置 bitcoin-core - - Bitcoin version - 比特币版本 + + CasinoCoin version + 莱特币版本 - + Usage: 使用: - - Send command to -server or bitcoind - 发送命令到服务器或者 bitcoind + + Send command to -server or casinocoind + 发送命令到服务器或者 casinocoind - + List commands 列出命令 - + Get help for a command 获得某条命令的帮助 - + Options: 选项: - - Specify configuration file (default: bitcoin.conf) - 指定配置文件 (默认为 bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + 指定配置文件 (默认为 casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - 指定 pid 文件 (默认为 bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + 指定 pid 文件 (默认为 casinocoind.pid) - - Generate coins - 生成货币 - - - - - Don't generate coins - 不要生成货币 - - - - + Specify data directory 指定数据目录 - + Set database cache size in megabytes (default: 25) 设置数据库缓冲区大小 (缺省: 25MB) - - Set database disk log size in megabytes (default: 100) - 设置数据库磁盘日志大小 (缺省: 100MB) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + 监听端口连接 <port> (缺省: 47950 or testnet: 17950) - - Specify connection timeout (in milliseconds) - 指定连接超时时间 (微秒) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - 监听端口连接 <port> (缺省: 8333 or testnet: 18333) - - - + Maintain at most <n> connections to peers (default: 125) 最大连接数 <n> (缺省: 125) - - Connect only to the specified node - 只连接到指定节点 - - - - + Connect to a node to retrieve peer addresses, and disconnect 连接一个节点并获取对端地址, 然后断开连接 - + Specify your own public address 指定您的公共地址 - - Only connect to nodes in network <net> (IPv4 or IPv6) - 仅连接指定网络中的节点 <net> (IPv4 or IPv6) - - - - Try to discover public IP address (default: 1) - 尝试发现公共IP地址 (缺省: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - 绑定指定地址. IPv6 使用 [host]:port - - - + Threshold for disconnecting misbehaving peers (default: 100) Threshold for disconnecting misbehaving peers (缺省: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Number of seconds to keep misbehaving peers from reconnecting (缺省: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - Maximum per-connection receive buffer, <n>*1000 bytes (缺省: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + 设置RPC监听端口%u时发生错误, IPv4:%s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - Maximum per-connection send buffer, <n>*1000 bytes (缺省: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + JSON-RPC连接监听端口<port> (缺省:47970 testnet:17970) - - Detach block and address databases. Increases shutdown time (default: 0) - 分离区块数据库和地址数据库. 会延升关闭时间 (缺省: 0) - - - + Accept command line and JSON-RPC commands 接受命令行和 JSON-RPC 命令 - + Run in the background as a daemon and accept commands 在后台运行并接受命令 - + Use the test network 使用测试网络 - - Output extra debugging information - 输出调试信息 + + Accept connections from outside (default: 1 if no -proxy or -connect) + 接受来自外部的连接 (缺省: 如果不带 -proxy or -connect 参数设置为1) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, 您必须在配置文件设置rpcpassword: + %s +建议您使用下面的随机密码: +rpcuser=casinocoinrpc +rpcpassword=%s +(您无需记住此密码) +用户名和密码 必! 须! 不一样。 +如果配置文件不存在,请自行建立一个只有所有者拥有只读权限的文件。 +推荐您开启提示通知以便收到错误通知, +像这样: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + 在IPv6模式下设置RPC监听端口 %u 失败,返回到IPv4模式: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + 绑定指定的IP地址开始监听。IPv6地址请使用[host]:port 格式 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + 无法给数据目录 %s上锁。本软件可能已经在运行。 + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + 错误:该交易被拒绝!发生这种错误的原因可能是:钱包中的莱特币已经被用掉,有可能您复制了wallet.dat钱包文件,然后用复制的钱包文件支付了莱特币,但是这个钱包文件中没有记录。 + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + 错误:因为该交易的数量、复杂度或者动用了刚收到不久的资金,您需要支付不少于%s的交易费用。 + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + 当收到相关通知时执行命令(命令行中的 %s 的替换为消息) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + 当最佳区块变化时执行命令 (命令行中的 %s 会被替换成区块哈希值) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + 这是测试用的预发布版本 - 请谨慎使用 - 不要用来挖矿,或者在正式商用环境下使用 + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + 警告:-paytxfee 交易费设置得太高了!每笔交易都将支付交易费。 + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + 警告:显示的交易可能不正确!您需要升级客户端软件,或者网络上的其他节点需要升级。 + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + 警告:请检查电脑的日期时间设置是否正确!时间错误可能会导致莱特币客户端运行异常。 + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + 警告:钱包文件wallet.dat读取失败!最重要的公钥、私钥数据都没有问题,但是交易记录或地址簿数据不正确,或者存在数据丢失。 + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + 警告:钱包文件wallet.dat损坏! 原始的钱包文件已经备份到%s目录下并重命名为{timestamp}.bak 。如果您的账户余额或者交易记录不正确,请使用您的钱包备份文件恢复。 + + + + Attempt to recover private keys from a corrupt wallet.dat + 尝试从损坏的钱包文件wallet.dat中恢复私钥 + + + + Block creation options: + 数据块创建选项: + + + + Connect only to the specified node(s) + 仅连接到指定节点 + + + + Corrupted block database detected + 检测发现数据块数据库损坏。请使用 -reindex参数重启客户端。 + + + + Discover own IP address (default: 1 when listening and no -externalip) + 发现自己的IP地址(缺省:不带 -externalip 参数监听时设置为1) + + + + Do you want to rebuild the block database now? + 你想现在就重建块数据库吗? + + + + Error initializing block database + 初始化数据块数据库出错 + + + + Error initializing wallet database environment %s! + Error initializing wallet database environment %s! + + + + Error loading block database + 导入数据块数据库出错 + + + + Error opening block database + 导入数据块数据库出错 + + + + Error: Disk space is low! + 错误:磁盘剩余空间低! + + + + Error: Wallet locked, unable to create transaction! + 错误:钱包被锁定,无法创建交易! + + + + Error: system error: + 错误:系统出错。 + + + + Failed to listen on any port. Use -listen=0 if you want this. + 监听端口失败。请使用 -listen=0 参数。 + + + + Failed to read block info + 无法读取数据块信息 + + + + Failed to read block + 读取数据块失败 + + + + Failed to sync block index + 无法同步数据块索引 + + + + Failed to write block index + 无法写入数据块索引 + + + + Failed to write block info + 无法写入数据块信息 + + + + Failed to write block + 无法写数据块 + + + + Failed to write file info + 无法写入文件信息 + + + + Failed to write to coin database + 无法写入coin数据库 + + + + Failed to write transaction index + 无法写入交易索引 + + + + Failed to write undo data + 无法写入回滚信息 + + + + Find peers using DNS lookup (default: 1 unless -connect) + 通过DNS查找节点(缺省:1 除非使用 -connect 选项) + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + 启动时检测多少个数据块(缺省:288,0=所有) + + + + How thorough the block verification is (0-4, default: 3) + How thorough the block verification is (0-4, default: 3) + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + 重新为当前的blk000??.dat文件建立索引 + + + + Set the number of threads to service RPC calls (default: 4) + 设置使用调用服务 RPC 的线程数量(默认:4) + + + + Verifying blocks... + 正在验证数据库的完整性... + + + + Verifying wallet... + 正在检测钱包的完整性... + + + + Imports blocks from external blk000??.dat file + 从blk000??.dat文件导入数据块 + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + 信息 + + + + Invalid -tor address: '%s' + 非法的 -tor 地址:'%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + 维护一份完整的交易索引(缺省:0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + 每个连接的最大接收缓存,<n>*1000 字节(缺省:5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + 每个连接的最大发送缓存,<n>*1000 字节(缺省:1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + 仅接受符合客户端检查点设置的数据块文件 + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + 仅连接至指定网络的节点<net>(IPv4, IPv6 或者 Tor) + + + + Output extra debugging information. Implies all other -debug* options + 输出额外的调试信息。打开所有 -debug* 开关 + + + + Output extra network debugging information + 输出额外的网络调试信息 + + + Prepend debug output with timestamp 为调试输出信息添加时间戳 - + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL选项:(参见CasinoCoin Wiki关于SSL设置栏目) + + + + Select the version of socks proxy to use (4-5, default: 5) + 请选择Socks代理服务器版本 (4 或 5, 缺省: 5) + + + Send trace/debug info to console instead of debug.log file 跟踪/调试信息输出到控制台,不输出到debug.log文件 - + Send trace/debug info to debugger 跟踪/调试信息输出到 调试器debugger - + + Set maximum block size in bytes (default: 250000) + 设置最大数据块大小(缺省:250000) + + + + Set minimum block size in bytes (default: 0) + 设置最小数据块大小(缺省:0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + 客户端启动时压缩debug.log文件(缺省:no-debug模式时为1) + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + 设置连接超时时间(缺省:5000毫秒) + + + + System error: + 系统错误: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + 使用UPnp映射监听端口(缺省: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + 使用UPnp映射监听端口(缺省: 监听状态设为1) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + 使用代理服务器访问隐藏服务(缺省:同 -proxy) + + + Username for JSON-RPC connections JSON-RPC连接用户名 - + + Warning + 警告 + + + + Warning: This version is obsolete, upgrade required! + 警告:该软件版本已过时,请升级! + + + + You need to rebuild the databases using -reindex to change -txindex + You need to rebuild the databases using -reindex to change -txindex + + + + wallet.dat corrupt, salvage failed + 钱包文件wallet.dat损坏,抢救备份失败 + + + Password for JSON-RPC connections JSON-RPC连接密码 - - Listen for JSON-RPC connections on <port> (default: 8332) - JSON-RPC连接监听<端口> (默认为 8332) - - - - + Allow JSON-RPC connections from specified IP address 允许从指定IP接受到的JSON-RPC连接 - + Send commands to node running on <ip> (default: 127.0.0.1) 向IP地址为 <ip> 的节点发送指令 (缺省: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - 当最佳区块变化时执行命令 (命令行中的 %s 会被替换成区块哈希值) + 当最佳数据块变化时执行命令 (命令行中的 %s 会被替换成数据块哈希值) - + Upgrade wallet to latest format 将钱包升级到最新的格式 - + Set key pool size to <n> (default: 100) 设置密钥池大小为 <n> (缺省: 100) - + Rescan the block chain for missing wallet transactions 重新扫描数据链以查找遗漏的交易 - - How many blocks to check at startup (default: 2500, 0 = all) - 启动时需检查的区块数量 (缺省: 2500, 设置0为检查所有区块) - - - - How thorough the block verification is (0-6, default: 1) - 需要几个确认 (0-6个, 缺省: 1个) - - - - Imports blocks from external blk000?.dat file - 从外来文件 blk000?.dat 导入区块数据 - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL 选项: (SSL 安装教程具体见比特币维基百科) - - - - + Use OpenSSL (https) for JSON-RPC connections 为 JSON-RPC 连接使用 OpenSSL (https)连接 - + Server certificate file (default: server.cert) 服务器证书 (默认为 server.cert) - + Server private key (default: server.pem) 服务器私钥 (默认为 server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) 可接受的加密器 (默认为 TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - 警告: 磁盘剩余空间不多了 - - - + This help message 该帮助信息 - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - 无法给数据目录 %s 加锁。比特币进程可能已在运行。 - - - - Bitcoin - 比特币 - - - + Unable to bind to %s on this computer (bind returned error %d, %s) 无法绑定本机端口 %s (返回错误消息 %d, %s) - + Connect through socks proxy 通过 socks 代理连接 - - Select the version of socks proxy to use (4 or 5, 5 is default) - 选择 socks 代理版本 (socks4 或 socks5, 缺省为socks5) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - 连接指定网络时不使用代理 <net> (IPv4 or IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect 使用 -addnode, -seednode 和 -connect选项时允许DNS查找 - - Pass DNS requests to (SOCKS5) proxy - 将 DNS 请求传递给 (SOCKS5) 代理 - - - + Loading addresses... 正在加载地址... - - Error loading blkindex.dat - blkindex.dat文件加载错误 - - - + Error loading wallet.dat: Wallet corrupted wallet.dat钱包文件加载错误:钱包损坏 - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - wallet.dat钱包文件加载错误:请升级到最新Bitcoin客户端 + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + wallet.dat钱包文件加载错误:请升级到最新CasinoCoin客户端 - - Wallet needed to be rewritten: restart Bitcoin to complete - 钱包文件需要重写:请退出并重新启动Bitcoin客户端 + + Wallet needed to be rewritten: restart CasinoCoin to complete + 钱包文件需要重写:请退出并重新启动CasinoCoin客户端 - + Error loading wallet.dat wallet.dat钱包文件加载错误 - + Invalid -proxy address: '%s' 非法的代理地址: '%s' - - Unknown network specified in -noproxy: '%s' - 被指定的是未知网络 -noproxy: '%s' - - - + Unknown network specified in -onlynet: '%s' 被指定的是未知网络 -onlynet: '%s' - + Unknown -socks proxy version requested: %i 被指定的是未知socks代理版本: %i - + Cannot resolve -bind address: '%s' 无法解析 -bind 端口地址: '%s' - - Not listening on any port - 未监听任何端口 - - - + Cannot resolve -externalip address: '%s' 无法解析 -externalip 地址: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' 非法金额 -paytxfee=<amount>: '%s' - - Error: could not start node - 错误: 无法启动节点 - - - - Error: Wallet locked, unable to create transaction - 错误: 钱包被锁,无法创建新的交易 - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - 错误: 该交易需支付到少 %s 的交易费,原因可能是该交易数量太小、构成太复杂或者使用了新近接收到的比特币 - - - - Error: Transaction creation failed - 错误:交易创建失败。 - - - - Sending... - 发送中 - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - 错误:交易被拒绝。这种情况通常发生在您钱包中的一些货币已经被消费之后,比如您使用了一个wallet.dat的副本,而货币在那个副本中已经被消费,但在当前钱包中未被标记为已消费。 - - - + Invalid amount 金额不对 - + Insufficient funds 金额不足 - + Loading block index... - 加载区块索引... + 加载数据块索引... - + Add a node to connect to and attempt to keep the connection open 添加节点并与其保持连接 - - Unable to bind to %s on this computer. Bitcoin is probably already running. - 无法在本机绑定 %s 端口 . 比特币客户端软件可能已经在运行. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + 无法在本机绑定 %s 端口 . 莱特币客户端软件可能已经在运行. - - Find peers using internet relay chat (default: 0) - 通过IRC聊天室查找网络上的比特币节点 (缺省: 0) - - - - Accept connections from outside (default: 1) - 接受来自外部的连接 (缺省: 1) - - - - Find peers using DNS lookup (default: 1) - 通过DNS查找网络上的比特币节点 (缺省: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - 使用UPnP映射监听端口 (缺省: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - 使用UPnP映射监听端口 (缺省: 0) - - - + Fee per KB to add to transactions you send 每发送1KB交易所需的费用 - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - 警告: -paytxfee 交易费用设得有点高. 每当您发送一笔交易,将会向网络支付这么多的交易费. - - - + Loading wallet... 正在加载钱包... - + Cannot downgrade wallet 无法降级钱包格式 - - Cannot initialize keypool - 无法初始化 keypool - - - + Cannot write default address 无法写入缺省地址 - + Rescanning... 正在重新扫描... - + Done loading 加载完成 - + To use the %s option 使用 %s 选项 - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, 您必须在配置文件中加入选项 rpcpassword : - %s -建议您使用下面的随机密码: -rpcuser=bitcoinrpc -rpcpassword=%s -(您无需记忆该密码) -如果配置文件不存在,请新建,并将文件权限设置为仅允许文件所有者读取. - - - + Error 错误 - - An error occured while setting up the RPC port %i for listening: %s - 将端口 %i 设置为监听端口时发生错误: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. @@ -2538,10 +2956,5 @@ If the file does not exist, create it with owner-readable-only file permissions. %s 如果配置文件不存在,请新建,并将文件权限设置为仅允许文件所有者读取. - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - 警告:请确定您当前计算机的日期和时间是正确的。比特币将无法在错误的时间下正常工作。 - \ 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 c2b318e..23bec3f 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -3,122 +3,160 @@ AboutDialog - - About Bitcoin - 關於位元幣 + + About CasinoCoin + 關於莱特幣 - - <b>Bitcoin</b> version - <b>位元幣</b>版本 + + <b>CasinoCoin</b> version + <b>莱特幣</b>版本 - - Copyright © 2009-2012 Bitcoin Developers - + + This is experimental software. -Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - 版權為 Bitcoin 開發人員自西元 2009 至 2012 年起所有 + +這是一套實驗性的軟體. -這是個實驗性的軟體. - -此軟體依據 MIX/X11 軟體授權條款散布, 詳情請見附帶的 license.txt 檔案, 或是以下網站: http://www.opensource.org/licenses/mit-license.php. +此軟體是依據 MIT/X11 軟體授權條款散布, 詳情請見附帶的 COPYING 檔案, 或是以下網站: http://www.opensource.org/licenses/mit-license.php. 此產品也包含了由 OpenSSL Project 所開發的 OpenSSL Toolkit (http://www.openssl.org/) 軟體, 由 Eric Young (eay@cryptsoft.com) 撰寫的加解密軟體, 以及由 Thomas Bernard 所撰寫的 UPnP 軟體. + + + Copyright + 版權 + + + + The CasinoCoin developers + 莱特幣開發人員 + AddressBookPage - + Address Book 位址簿 - - These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - 這是你用來收款的位元幣位址. 你可以提供不同的位址給不同的付款人, 來追蹤是誰支付給你. - - - + Double-click to edit address or label 點兩下來修改位址或標記 - + Create a new address 產生新位址 - + Copy the currently selected address to the system clipboard 複製目前選取的位址到系統剪貼簿 - + &New Address 新增位址 - + + These are your CasinoCoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + 這些是你用來收款的莱特幣位址. 你可以提供不同的位址給不同的付款人, 來追蹤是誰支付給你. + + + &Copy Address 複製位址 - + Show &QR Code 顯示 &QR 條碼 - - Sign a message to prove you own this address - 簽署一則訊息來證明你擁有這個位址 + + Sign a message to prove you own a CasinoCoin address + 簽署訊息是用來證明莱特幣位址是你的 - - &Sign Message - 簽署訊息 + + Sign &Message + 訊息簽署 - - Delete the currently selected address from the list. Only sending addresses can be deleted. - 從列表中刪除目前選取的位址. 只能夠刪除付款位址. + + Delete the currently selected address from the list + 從列表中刪除目前選取的位址 - + + Export the data in the current tab to a file + 將目前分頁的資料匯出存成檔案 + + + + &Export + 匯出 + + + + Verify a message to ensure it was signed with a specified CasinoCoin address + 驗證訊息是用來確認訊息是用指定的莱特幣位址簽署的 + + + + &Verify Message + 訊息驗證 + + + &Delete 刪除 - + + These are your CasinoCoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 這是你用來付款的莱特幣位址. 在付錢之前, 務必要檢查金額和收款位址是否正確. + + + Copy &Label 複製標記 - + &Edit 編輯 - + + Send &Coins + 付錢 + + + Export Address Book Data 匯出位址簿資料 - + Comma separated file (*.csv) 逗號區隔資料檔 (*.csv) - + Error exporting - 資料匯出有誤 + 匯出失敗 - + Could not write to file %1. 無法寫入檔案 %1. @@ -126,17 +164,17 @@ This product includes software developed by the OpenSSL Project for use in the O AddressTableModel - + Label 標記 - + Address 位址 - + (no label) (沒有標記) @@ -144,432 +182,460 @@ This product includes software developed by the OpenSSL Project for use in the O AskPassphraseDialog - + Passphrase Dialog 密碼對話視窗 - + Enter passphrase 輸入密碼 - + New passphrase 新的密碼 - + Repeat new passphrase 重複新密碼 - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - 輸入錢包的新密碼.<br/>請用<b>10個以上的字元</b>, 或是<b>8個以上的字詞</b>. + 輸入錢包的新密碼.<br/>請用<b>10個以上的字元</b>, 或是<b>8個以上的單字</b>. - + Encrypt wallet 錢包加密 - + This operation needs your wallet passphrase to unlock the wallet. 這個動作需要用你的錢包密碼來解鎖 - + Unlock wallet 錢包解鎖 - + This operation needs your wallet passphrase to decrypt the wallet. 這個動作需要用你的錢包密碼來解密 - + Decrypt wallet 錢包解密 - + Change passphrase 變更密碼 - + Enter the old and new passphrase to the wallet. 輸入錢包的新舊密碼. - + Confirm wallet encryption 錢包加密確認 - - WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! -Are you sure you wish to encrypt your wallet? - 警告: 如果將錢包加密後忘記密碼, 你會<b>失去其中所有的位元幣</b>! -你確定要將錢包加密嗎? + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>! + 警告: 如果將錢包加密後忘記密碼, 你會<b>失去其中所有的莱特幣</b>! - - + + Are you sure you wish to encrypt your wallet? + 你確定要將錢包加密嗎? + + + + 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. + 重要: 請改用新產生有加密的錢包檔, 來取代之前錢包檔的備份. 為了安全性的理由, 當你開始使用新的有加密的錢包時, 舊錢包的備份就不能再使用了. + + + + + Warning: The Caps Lock key is on! + 警告: 大寫字母鎖定作用中! + + + + Wallet encrypted 錢包已加密 - - Bitcoin 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. - 位元幣現在要關閉以完成加密程序. 請記住, 加密錢包無法完全防止入侵電腦的惡意程式偷取你的位元幣. + + CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer. + 莱特幣現在要關閉以完成加密程序. 請記住, 加密錢包無法完全防止入侵電腦的惡意程式偷取你的莱特幣. - - - Warning: The Caps Lock key is on. - 警告: 鍵盤輸入鎖定為大寫字母中. - - - - - - + + + + Wallet encryption failed 錢包加密失敗 - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - 錢包加密因程式內部有誤而失敗. 你的錢包還是沒有加密. + 錢包加密因程式內部錯誤而失敗. 你的錢包還是沒有加密. - - + + The supplied passphrases do not match. 提供的密碼不符. - + Wallet unlock failed 錢包解鎖失敗 - - - + + + The passphrase entered for the wallet decryption was incorrect. 用來解密錢包的密碼輸入錯誤. - + Wallet decryption failed 錢包解密失敗 - - Wallet passphrase was succesfully changed. + + Wallet passphrase was successfully changed. 錢包密碼變更成功. BitcoinGUI - - Bitcoin Wallet - 位元幣錢包 - - - + Sign &message... 訊息簽署... - - Show/Hide &Bitcoin - 顯示/隱藏位元幣 - - - + Synchronizing with network... 網路同步中... - + &Overview 總覽 - + Show general overview of wallet 顯示錢包一般總覽 - + &Transactions 交易 - + Browse transaction history 瀏覽交易紀錄 - - &Address Book - 位址簿 - - - + Edit the list of stored addresses and labels - 編輯儲存位址與標記的列表 + 編輯位址與標記的儲存列表 - - &Receive coins - 收錢 - - - + Show the list of addresses for receiving payments 顯示收款位址的列表 - - &Send coins - 付錢 - - - - Prove you control an address - 證明你控制一個位址 - - - + E&xit 結束 - + Quit application 結束應用程式 - - &About %1 - 關於%1 + + Show information about CasinoCoin + 顯示莱特幣相關資訊 - - Show information about Bitcoin - 顯示位元幣相關資訊 - - - + About &Qt 關於 &Qt - + Show information about Qt 顯示有關於 Qt 的資訊 - + &Options... 選項... - + &Encrypt Wallet... 錢包加密... - + &Backup Wallet... 錢包備份... - + &Change Passphrase... 密碼變更... - - - ~%n block(s) remaining - 剩下 ~%n 個區塊 + + + Importing blocks from disk... + 從磁碟匯入區塊中... - - Downloaded %1 of %2 blocks of transaction history (%3% done). - 已下載了全部 %2 個中的 %1 個交易紀錄區塊 (已完成 %3%). + + Reindexing blocks on disk... + 重建磁碟區塊索引中... - - &Export... - 匯出... + + Send coins to a CasinoCoin address + 付錢到莱特幣位址 - - Send coins to a Bitcoin address - 付錢到一個位元幣位址 + + Modify configuration options for CasinoCoin + 修改莱特幣的設定選項 - - Modify configuration options for Bitcoin - 修改位元幣的設定選項 - - - - Show or hide the Bitcoin window - 顯示或隱藏位元幣的視窗 - - - - Export the data in the current tab to a file - 將目前分頁的資料匯出存成檔案 - - - - Encrypt or decrypt wallet - 將錢包加解密 - - - + Backup wallet to another location 將錢包備份到其它地方 - + Change the passphrase used for wallet encryption 變更錢包加密用的密碼 - + &Debug window 除錯視窗 - + Open debugging and diagnostic console 開啓除錯與診斷主控台 - + &Verify message... - 訊息驗證... + 驗證訊息... - - Verify a message signature - 驗證訊息簽章 + + + CasinoCoin + 莱特幣 - + + Wallet + 錢包 + + + + &Send + 付出 + + + + &Receive + 收受 + + + + &Addresses + 位址 + + + + &About CasinoCoin + 關於莱特幣 + + + + &Show / Hide + 顯示或隱藏 + + + + Show or hide the main Window + 顯示或隱藏主視窗 + + + + Encrypt the private keys that belong to your wallet + 將屬於你的錢包的密鑰加密 + + + + Sign messages with your CasinoCoin addresses to prove you own them + 用莱特幣位址簽署訊息來證明那是你的 + + + + Verify messages to ensure they were signed with specified CasinoCoin addresses + 驗證訊息來確認是用指定的莱特幣位址簽署的 + + + &File 檔案 - + &Settings 設定 - + &Help 求助 - + Tabs toolbar 分頁工具列 - - Actions toolbar - 動作工具列 - - - - + + [testnet] [testnet] - - - Bitcoin client - 位元幣客戶軟體 + + CasinoCoin client + 莱特幣客戶端軟體 - - %n active connection(s) to Bitcoin network - 與位元幣網路有 %n 個連線在使用中 + + %n active connection(s) to CasinoCoin network + 與莱特幣網路有 %n 個連線在使用中 - - Downloaded %1 blocks of transaction history. - 已下載了 %1 個交易紀錄的區塊. - - - - %n second(s) ago - %n 秒鐘前 - - - - %n minute(s) ago - %n 分鐘前 - - - - %n hour(s) ago - %n 小時前 - - - - %n day(s) ago - %n 天前 + + No block source available... + 目前沒有區塊來源... - + + Processed %1 of %2 (estimated) blocks of transaction history. + 已處理了估計全部 %2 個中的 %1 個區塊的交易紀錄. + + + + Processed %1 blocks of transaction history. + 已處理了 %1 個區塊的交易紀錄. + + + + %n hour(s) + %n 個小時 + + + + %n day(s) + %n 天 + + + + %n week(s) + %n 個星期 + + + + %1 behind + 落後 %1 + + + + Last received block was generated %1 ago. + 最近收到的區塊是在 %1 之前生產出來. + + + + Transactions after this will not yet be visible. + 會看不見在這之後的交易. + + + + Error + 錯誤 + + + + Warning + 警告 + + + + Information + 資訊 + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + 這筆交易的資料大小超過限制了. 你還是可以付出 %1 的費用來傳送, 這筆費用會付給處理你的交易的節點, 並幫助維持整個網路. 你願意支付這項費用嗎? + + + Up to date 最新狀態 - + Catching up... 進度追趕中... - - Last received block was generated %1. - 最近收到的區塊產生於 %1. - - - - This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - 這筆交易的資料大小超過限制了. 你還是可以付出 %1 的費用來傳送. 這筆費用會付給處理該筆交易的節點, 並幫助維持整個網路. 你願意支付這項費用嗎? - - - + Confirm transaction fee 確認交易手續費 - + Sent transaction 付款交易 - + Incoming transaction 收款交易 - + Date: %1 Amount: %2 Type: %3 @@ -581,539 +647,486 @@ Address: %4 位址: %4 - + + + URI handling + URI 處理 + + + + + URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters. + 無法解析 URI! 也許莱特幣位址無效或 URI 參數有誤. + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> 錢包<b>已加密</b>並且正<b>解鎖中</b> - + Wallet is <b>encrypted</b> and currently <b>locked</b> 錢包<b>已加密</b>並且正<b>上鎖中</b> - - Backup Wallet - 錢包備份 - - - - Wallet Data (*.dat) - 錢包資料檔 (*.dat) - - - - Backup Failed - 備份失敗 - - - - There was an error trying to save the wallet data to the new location. - 儲存錢包資料到新的地方時發生錯誤 - - - - A fatal error occured. Bitcoin can no longer continue safely and will quit. - 發生了致命的錯誤. 位元幣程式將無法繼續安全執行, 只好結束. + + A fatal error occurred. CasinoCoin can no longer continue safely and will quit. + 發生了致命的錯誤. 莱特幣程式無法再繼續安全執行, 只好結束. ClientModel - + Network Alert 網路警報 - - DisplayOptionsPage - - - Display - 顯示 - - - - default - 預設 - - - - The user interface language can be set here. This setting will only take effect after restarting Bitcoin. - 可以在這裡設定使用者介面的語言. 這個設定在位元幣程式重啓後才會生效. - - - - User Interface &Language: - 使用界面語言 - - - - &Unit to show amounts in: - 金額顯示單位: - - - - Choose the default subdivision unit to show in the interface, and when sending coins - 選擇操作界面與付錢時預設顯示的細分單位 - - - - &Display addresses in transaction list - 在交易列表顯示位址 - - - - Whether to show Bitcoin addresses in the transaction list - 是否要在交易列表中顯示位元幣位址 - - - - Warning - 警告 - - - - This setting will take effect after restarting Bitcoin. - 這個設定會在位元幣程式重啓後生效. - - EditAddressDialog - + Edit Address 編輯位址 - + &Label 標記 - + The label associated with this address book entry 與這個位址簿項目關聯的標記 - + &Address 位址 - + The address associated with this address book entry. This can only be modified for sending addresses. - 與這個位址簿項目關聯的位址. 只能修改付款位址. + 與這個位址簿項目關聯的位址. 付款位址才能被更改. - + New receiving address 新收款位址 - + New sending address - 新付款位址 + 新增付款位址 - + Edit receiving address 編輯收款位址 - + Edit sending address 編輯付款位址 - + The entered address "%1" is already in the address book. 輸入的位址"%1"已存在於位址簿中. - - The entered address "%1" is not a valid Bitcoin address. - 輸入的位址 "%1" 並不是有效的位元幣位址. + + The entered address "%1" is not a valid CasinoCoin address. + 輸入的位址 "%1" 並不是有效的莱特幣位址. - + Could not unlock wallet. 無法將錢包解鎖. - + New key generation failed. 新密鑰產生失敗. - HelpMessageBox + GUIUtil::HelpMessageBox - - - Bitcoin-Qt - 位元幣-Qt + + + CasinoCoin-Qt + 莱特幣-Qt - + version 版本 - + Usage: 用法: - - options - 選項 + + command-line options + 命令列選項 - + UI options 使用界面選項 - + Set language, for example "de_DE" (default: system locale) 設定語言, 比如說 "de_DE" (預設: 系統語系) - + Start minimized 啓動時最小化 - + Show splash screen on startup (default: 1) 顯示啓動畫面 (預設: 1) - MainOptionsPage + OptionsDialog - - Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. - 關掉程式時卸載區塊與位址的資料庫. 表示說資料庫會被搬到別的資料目錄去, 且會造成程式關掉的比較慢. 錢包則總是會被卸載. + + Options + 選項 - + + &Main + 主要 + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + 非必要的交易手續費, 以 kB 為計費單位, 且有助於縮短你的交易處理時間. 大部份交易資料的大小是 1 kB. + + + Pay transaction &fee 付交易手續費 - - Main - 主要 + + Automatically start CasinoCoin after logging in to the system. + 在登入系統後自動啓動莱特幣. - - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - 非必要的交易手續費, 以 kB 為計費單位, 且有助於縮短你的交易處理時間. 大部份交易的資料大小是 1 kB. 建議設定為 0.01 元. + + &Start CasinoCoin on system login + 系統登入時啟動莱特幣 - - &Start Bitcoin on system login - 系統登入時啟動位元幣 + + Reset all client options to default. + 回復所有客戶端軟體選項成預設值. - - Automatically start Bitcoin after logging in to the system - 在登入系統後自動啓動位元幣 + + &Reset Options + 選項回復 - - &Detach databases at shutdown - 關閉時卸載資料庫 - - - - MessagePage - - - Sign Message - 訊息簽署 - - - - You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - 你可以用你的位址來簽署訊息, 以證明你對它的所有權. 但是請小心, 不要簽署語意含糊不清的內容, 因為釣魚式詐騙可能會用騙你簽署的手法來冒充是你. 只有在語句中的細節你都同意時才簽署. - - - - The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 用來簽署訊息的位址 (比如說 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - Choose adress from address book - 從位址簿中選一個位址 - - - - Alt+A - Alt+A - - - - Paste address from clipboard - 從剪貼簿貼上位址 - - - - Alt+P - Alt+P - - - - Enter the message you want to sign here - 在這裡輸入你想簽署的訊息 - - - - Copy the current signature to the system clipboard - 複製目前的簽章到系統剪貼簿 - - - - &Copy Signature - 複製簽章 - - - - Reset all sign message fields - 重置所有訊息簽署欄位 - - - - Clear &All - 全部清掉 - - - - Click "Sign Message" to get signature - 按"簽署訊息"來取得簽章 - - - - Sign a message to prove you own this address - 簽署一則訊息來證明你擁有這個位址 - - - - &Sign Message - 簽署訊息 - - - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 輸入位元幣位址 (比如說 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - - - - - Error signing - 簽署發生錯誤 - - - - %1 is not a valid address. - %1 不是個有效的位址. - - - - %1 does not refer to a key. - %1 沒有指到任何密鑰. - - - - Private key for %1 is not available. - 沒有 %1 的密鑰. - - - - Sign failed - 簽署失敗 - - - - NetworkOptionsPage - - - Network + + &Network 網路 - + + Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled. + 自動在路由器上開啟 CasinoCoin 的客戶端通訊埠. 只有在你的路由器支援 UPnP 且開啟時才有作用. + + + Map port using &UPnP 用 &UPnP 設定通訊埠對應 - - Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - 自動在路由器上開啟 Bitcoin 的客戶端通訊埠. 只有在你的路由器支援 UPnP 且開啟時才有作用. + + Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor). + 透過 SOCKS 代理伺服器連線至莱特幣網路 (比如說要透過 Tor 連線). - - &Connect through SOCKS4 proxy: - 透過 SOCKS4 代理伺服器連線: + + &Connect through SOCKS proxy: + 透過 SOCKS 代理伺服器連線: - - Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor) - 透過 SOCKS4 代理伺服器連線至位元幣網路 (比如說透過 Tor) - - - + Proxy &IP: 代理伺服器位址: - - &Port: - 通訊埠: - - - + IP address of the proxy (e.g. 127.0.0.1) 代理伺服器的網際網路位址 (比如說 127.0.0.1) - - Port of the proxy (e.g. 1234) - 代理伺服器的通訊埠 (比如說 1234) + + &Port: + 通訊埠: - - - OptionsDialog - - Options - 選項 + + Port of the proxy (e.g. 9050) + 代理伺服器的通訊埠 (比如說 9050) + + + + SOCKS &Version: + SOCKS 協定版本: + + + + SOCKS version of the proxy (e.g. 5) + 代理伺服器的 SOCKS 協定版本 (比如說 5) + + + + &Window + 視窗 + + + + Show only a tray icon after minimizing the window. + 最小化視窗後只在通知區域顯示圖示 + + + + &Minimize to the tray instead of the taskbar + 最小化至通知區域而非工作列 + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + 當視窗關閉時將其最小化, 而非結束應用程式. 當勾選這個選項時, 應用程式只能用選單中的結束來停止執行. + + + + M&inimize on close + 關閉時最小化 + + + + &Display + 顯示 + + + + User Interface &language: + 使用界面語言 + + + + The user interface language can be set here. This setting will take effect after restarting CasinoCoin. + 可以在這裡設定使用者介面的語言. 這個設定在莱特幣程式重啓後才會生效. + + + + &Unit to show amounts in: + 金額顯示單位: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + 選擇操作界面與付錢時預設顯示的細分單位. + + + + Whether to show CasinoCoin addresses in the transaction list or not. + 是否要在交易列表中顯示莱特幣位址. + + + + &Display addresses in transaction list + 在交易列表顯示位址 + + + + &OK + + + + + &Cancel + 取消 + + + + &Apply + 套用 + + + + default + 預設 + + + + Confirm options reset + 確認回復選項 + + + + Some settings may require a client restart to take effect. + 有些設定可能需要重新啓動客戶端軟體才會生效. + + + + Do you want to proceed? + 你想要就做下去嗎? + + + + + Warning + 警告 + + + + + This setting will take effect after restarting CasinoCoin. + 這個設定會在莱特幣程式重啓後生效. + + + + The supplied proxy address is invalid. + 提供的代理伺服器位址無效 OverviewPage - + Form 表單 - - - 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. - 顯示的資訊可能是過期的. 與位元幣網路的連線建立後, 你的錢包會自動和網路同步, 但這個步驟還沒完成. + + + The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet. + 顯示的資訊可能是過期的. 與莱特幣網路的連線建立後, 你的錢包會自動和網路同步, 但這個步驟還沒完成. - + Balance: 餘額: - - Number of transactions: - 交易次數: - - - + Unconfirmed: 未確認額: - + Wallet 錢包 - + + Immature: + 未熟成 + + + + Mined balance that has not yet matured + 尚未熟成的開採金額 + + + <b>Recent transactions</b> <b>最近交易</b> - + Your current balance 目前餘額 - + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance 尚未確認之交易的總額, 不包含在目前餘額中 - - Total number of transactions in wallet - 錢包中紀錄的總交易次數 - - - - + + out of sync 沒同步 + + PaymentServer + + + Cannot start casinocoin: click-to-pay handler + 無法啟動 casinocoin 隨按隨付處理器 + + QRCodeDialog - + QR Code Dialog QR 條碼對話視窗 - - QR Code - QR 條碼 - - - + Request Payment 付款單 - + Amount: 金額: - - BTC - BTC - - - + Label: 標記: - + Message: 訊息: - + &Save As... 儲存為... - + Error encoding URI into QR Code. - 將 URI 編碼成 QR 條碼時發生錯誤 + 將 URI 編碼成 QR 條碼失敗 - + + The entered amount is invalid, please check. + 輸入的金額無效, 請檢查看看. + + + Resulting URI too long, try to reduce the text for label / message. 造出的網址太長了,請把標籤或訊息的文字縮短再試看看. - + Save QR Code 儲存 QR 條碼 - + PNG Images (*.png) PNG 圖檔 (*.png) @@ -1121,125 +1134,146 @@ Address: %4 RPCConsole - - Bitcoin debug window - 位元幣除錯視窗 - - - + Client name - 客戶端程式名稱 + 客戶端軟體名稱 - - - - - - - - - + + + + + + + + + + N/A - + Client version - 客戶端程式版本 + 客戶端軟體版本 - + &Information 資訊 - - Client - 用戶端程式 + + Using OpenSSL version + 使用 OpenSSL 版本 - + Startup time 啓動時間 - + Network 網路 - + Number of connections 連線數 - + On testnet 位於測試網路 - + Block chain 區塊鎖鏈 - + Current number of blocks 目前區塊數 - + Estimated total blocks 估計總區塊數 - + Last block time 最近區塊時間 - - Debug logfile - 除錯紀錄檔 - - - - Open the Bitcoin debug logfile from the current data directory. This can take a few seconds for large logfiles. - 從目前的資料目錄下開啓位元幣的除錯紀錄檔. 當紀錄檔很大時可能要花好幾秒的時間. - - - + &Open 開啓 - + + Command-line options + 命令列選項 + + + + Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options. + 顯示莱特幣-Qt的求助訊息, 來取得可用的命令列選項列表. + + + + &Show + 顯示 + + + &Console 主控台 - + Build date 建置日期 - + + CasinoCoin - Debug window + 莱特幣 - 除錯視窗 + + + + CasinoCoin Core + 莱特幣核心 + + + + Debug log file + 除錯紀錄檔 + + + + Open the CasinoCoin debug log file from the current data directory. This can take a few seconds for large log files. + 從目前的資料目錄下開啓莱特幣的除錯紀錄檔. 當紀錄檔很大時可能要花好幾秒的時間. + + + Clear console 清主控台 - - Welcome to the Bitcoin RPC console. - 歡迎使用位元幣 RPC 主控台. + + Welcome to the CasinoCoin RPC console. + 歡迎使用莱特幣 RPC 主控台. - + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. 請用上下游標鍵來瀏覽歷史指令, 且可用 <b>Ctrl-L</b> 來清理畫面. - + Type <b>help</b> for an overview of available commands. 請打 <b>help</b> 來看可用指令的簡介. @@ -1247,109 +1281,109 @@ Address: %4 SendCoinsDialog - - - - - - - - + + + + + + + + Send Coins 付錢 - + Send to multiple recipients at once 一次付給多個人 - - &Add Recipient + + Add &Recipient 加收款人 - + Remove all transaction fields 移除所有交易欄位 - + Clear &All 全部清掉 - + Balance: 餘額: - + 123.456 BTC 123.456 BTC - + Confirm the send action 確認付款動作 - - &Send + + S&end 付出 - + <b>%1</b> to %2 (%3) <b>%1</b> 給 %2 (%3) - + Confirm send coins - 確認付出金額 + 確認要付錢 - + Are you sure you want to send %1? 確定要付出 %1 嗎? - + and - - The recepient address is not valid, please recheck. + + The recipient address is not valid, please recheck. 無效的收款位址, 請再檢查看看. - + The amount to pay must be larger than 0. 付款金額必須大於 0. - + The amount exceeds your balance. - 金額超過了餘額 + 金額超過餘額了. - + The total exceeds your balance when the %1 transaction fee is included. - 包含 %1 的交易手續費後, 總金額超過了你的餘額 + 包含 %1 的交易手續費後, 總金額超過你的餘額了. - + Duplicate address found, can only send to each address once per send operation. - 發現有重複的位址. 在一次付款動作中, 只能付給每個位址一次. + 發現有重複的位址. 每個付款動作中, 只能付給個別的位址一次. - - Error: Transaction creation failed. - 錯誤: 交易產生失敗. + + Error: Transaction creation failed! + 錯誤: 交易產生失敗! - + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. 錯誤: 交易被拒絕. 有時候會發生這種錯誤, 是因為你錢包中的一些錢已經被花掉了. 比如說你複製了錢包檔 wallet.dat, 然後用複製的錢包花掉了錢, 你現在所用的原來的錢包中卻沒有該筆交易紀錄. @@ -1357,217 +1391,456 @@ Address: %4 SendCoinsEntry - + Form 表單 - + A&mount: 金額: - + Pay &To: 付給: - - - Enter a label for this address to add it to your address book - 給這個位址輸入一個標記, 並加到位址簿中 + + The address to send the payment to (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 付款的目標位址 (比如說 Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) - + + + Enter a label for this address to add it to your address book + 輸入一個標記給這個位址, 並加到位址簿中 + + + &Label: 標記: - - The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 付款的目標位址 (比如說 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - - + Choose address from address book 從位址簿中選一個位址 - + Alt+A Alt+A - + Paste address from clipboard 從剪貼簿貼上位址 - + Alt+P Alt+P - + Remove this recipient 去掉這個收款人 - - Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - 輸入位元幣位址 (比如說 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 輸入莱特幣位址 (比如說 Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + 簽章 - 簽署或驗證訊息 + + + + &Sign Message + 訊息簽署 + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + 你可以用自己的位址來簽署訊息, 以證明你對它的所有權. 但是請小心, 不要簽署語意含糊不清的內容, 因為釣魚式詐騙可能會用騙你簽署的手法來冒充是你. 只有在語句中的細節你都同意時才簽署. + + + + The address to sign the message with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 用來簽署訊息的位址 (比如說 Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + + Choose an address from the address book + 從位址簿選一個位址 + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + 從剪貼簿貼上位址 + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + 在這裡輸入你想簽署的訊息 + + + + Signature + 簽章 + + + + Copy the current signature to the system clipboard + 複製目前的簽章到系統剪貼簿 + + + + Sign the message to prove you own this CasinoCoin address + 簽署訊息是用來證明這個莱特幣位址是你的 + + + + Sign &Message + 訊息簽署 + + + + Reset all sign message fields + 重置所有訊息簽署欄位 + + + + + Clear &All + 全部清掉 + + + + &Verify Message + 訊息驗證 + + + + Enter the signing 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. + 請在下面輸入簽署的位址, 訊息(請確認完整複製了所包含的換行, 空格, 跳位符號等等), 與簽章, 以驗證該訊息. 請小心, 除了訊息內容外, 不要對簽章本身過度解讀, 以避免被用"中間人攻擊法"詐騙. + + + + The address the message was signed with (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 簽署該訊息的位址 (比如說 Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Verify the message to ensure it was signed with the specified CasinoCoin address + 驗證訊息是用來確認訊息是用指定的莱特幣位址簽署的 + + + + Verify &Message + 訊息驗證 + + + + Reset all verify message fields + 重置所有訊息驗證欄位 + + + + + Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + 輸入莱特幣位址 (比如說 Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2) + + + + Click "Sign Message" to generate signature + 按"訊息簽署"來產生簽章 + + + + Enter CasinoCoin signature + 輸入莱特幣簽章 + + + + + The entered address is invalid. + 輸入的位址無效. + + + + + + + Please check the address and try again. + 請檢查位址是否正確後再試一次. + + + + + The entered address does not refer to a key. + 輸入的位址沒有指到任何密鑰. + + + + Wallet unlock was cancelled. + 錢包解鎖已取消. + + + + Private key for the entered address is not available. + 沒有所輸入位址的密鑰. + + + + Message signing failed. + 訊息簽署失敗. + + + + Message signed. + 訊息已簽署. + + + + The signature could not be decoded. + 無法將這個簽章解碼. + + + + + Please check the signature and try again. + 請檢查簽章是否正確後再試一次. + + + + The signature did not match the message digest. + 這個簽章與訊息的數位摘要不符. + + + + Message verification failed. + 訊息驗證失敗. + + + + Message verified. + 訊息已驗證. + + + + SplashScreen + + + The CasinoCoin developers + 莱特幣開發人員 + + + + [testnet] + [testnet] TransactionDesc - - Open for %1 blocks - 在 %1 個區塊內未定 - - - + Open until %1 在 %1 前未定 - - %1/offline? - %1/離線中? + + %1/offline + %1/離線中 - + %1/unconfirmed %1/未確認 - + %1 confirmations 經確認 %1 次 - - <b>Status:</b> - <b>狀態:</b> + + Status + 狀態 + + + + , broadcast through %n node(s) + , 已公告至 %n 個節點 - + + Date + 日期 + + + + Source + 來源 + + + + Generated + 生產出 + + + + + From + 來處 + + + + + + To + 目的 + + + + + own address + 自己的位址 + + + + label + 標籤 + + + + + + + + Credit + 入帳 + + + + matures in %n more block(s) + 將在 %n 個區塊產出後熟成 + + + + not accepted + 不被接受 + + + + + + + Debit + 出帳 + + + + Transaction fee + 交易手續費 + + + + Net amount + 淨額 + + + + Message + 訊息 + + + + Comment + 附註 + + + + Transaction ID + 交易識別碼 + + + + Generated coins must mature 120 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. + 生產出來的錢要再等 120 個區塊熟成之後, 才能夠花用. 當你產出區塊時, 它會被公布到網路上, 以被串連至區塊鎖鏈. 如果串連失敗了, 它的狀態就會變成"不被接受", 且不能被花用. 當你產出區塊的幾秒鐘內, 也有其他節點產出區塊的話, 有時候就會發生這種情形. + + + + Debug information + 除錯資訊 + + + + Transaction + 交易 + + + + Inputs + 輸入 + + + + Amount + 金額 + + + + true + + + + + false + + + + , has not been successfully broadcast yet , 尚未成功公告出去 - - - , broadcast through %1 node - , 已公告至 %1 個節點 + + + Open for %n more block(s) + 在接下來 %n 個區塊產出前未定 - - , broadcast through %1 nodes - , 已公告至 %1 個節點 - - - - <b>Date:</b> - <b>日期:</b> - - - - <b>Source:</b> Generated<br> - <b>來源:</b> 生產所得<br> - - - - - <b>From:</b> - <b>來自:</b> - - - + unknown 未知 - - - - - <b>To:</b> - <b>目的:</b> - - - - (yours, label: - (你的, 標記為: - - - - (yours) - (你的) - - - - - - - <b>Credit:</b> - <b>入帳:</b> - - - - (%1 matures in %2 more blocks) - (%1 將在 %2 個區塊產出後熟成) - - - - (not accepted) - (不被接受) - - - - - - <b>Debit:</b> - <b>出帳:</b> - - - - <b>Transaction fee:</b> - <b>交易手續費:</b> - - - - <b>Net amount:</b> - <b>淨額:</b> - - - - Message: - 訊息: - - - - Comment: - 附註: - - - - Transaction ID: - 交易識別碼: - - - - Generated coins must wait 120 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, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - 生產出來的錢要再等 120 個區塊產出之後, 才能夠花用. 當你產出區塊時, 它會被公布到網路上, 以被串連至區塊鎖鏈. 如果串連失敗了, 它的狀態就會變成"不被接受", 且不能被花用. 當你產出區塊的幾秒鐘內, 其他節點也產出了區塊的話, 有時候就會發生這種情形. - TransactionDescDialog - + Transaction details 交易明細 - + This pane shows a detailed description of the transaction 此版面顯示交易的詳細說明 @@ -1575,117 +1848,117 @@ Address: %4 TransactionTableModel - + Date 日期 - + Type 種類 - + Address 位址 - + Amount 金額 - - Open for %n block(s) - 在 %n 個區塊內未定 + + Open for %n more block(s) + 在接下來 %n 個區塊產出前未定 - + Open until %1 在 %1 前未定 - + Offline (%1 confirmations) 離線中 (經確認 %1 次) - + Unconfirmed (%1 of %2 confirmations) 未確認 (經確認 %1 次, 應確認 %2 次) - + Confirmed (%1 confirmations) 已確認 (經確認 %1 次) - - Mined balance will be available in %n more blocks - 生產金額將在 %n 個區塊產出後可用 + + Mined balance will be available when it matures in %n more block(s) + 開採金額將可在 %n 個區塊熟成後可用 - + This block was not received by any other nodes and will probably not be accepted! 沒有其他節點收到這個區塊, 也許它不被接受! - + Generated but not accepted - 產出但不被接受 + 生產出但不被接受 - + Received with 收受於 - + Received from 收受自 - + Sent to 付出至 - + Payment to yourself 付給自己 - + Mined 開採所得 - + (n/a) (不適用) - + Transaction status. Hover over this field to show number of confirmations. 交易狀態. 移動游標至欄位上方來顯示確認次數. - + Date and time that the transaction was received. 收到交易的日期與時間. - + Type of transaction. 交易的種類. - + Destination address of transaction. 交易的目標位址. - + Amount removed from or added to balance. 減去或加入至餘額的金額 @@ -1693,849 +1966,990 @@ Address: %4 TransactionView - - + + All 全部 - + Today 今天 - + This week 這週 - + This month 這個月 - + Last month 上個月 - + This year 今年 - + Range... 指定範圍... - + Received with 收受於 - + Sent to 付出至 - + To yourself 給自己 - + Mined 開採所得 - + Other 其他 - + Enter address or label to search 輸入位址或標記來搜尋 - + Min amount 最小金額 - + Copy address 複製位址 - + Copy label 複製標記 - + Copy amount 複製金額 - + + Copy transaction ID + 複製交易識別碼 + + + Edit label 編輯標記 - + Show transaction details 顯示交易明細 - + Export Transaction Data 匯出交易資料 - + Comma separated file (*.csv) 逗號分隔資料檔 (*.csv) - + Confirmed 已確認 - + Date 日期 - + Type 種類 - + Label 標記 - + Address 位址 - + Amount 金額 - + ID 識別碼 - + Error exporting - 匯出錯誤 + 匯出失敗 - + Could not write to file %1. 無法寫入至 %1 檔案. - + Range: 範圍: - + to - - VerifyMessageDialog - - - Verify Signed Message - 驗證簽署過的訊息 - - - - Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message. - 請在下面輸入訊息與簽章(有些字元是看不到的, 如換行, 空格, 跳位符號等, 請小心並正確地複製), 以獲知用來簽署該訊息的位元幣位址. - - - - Verify a message and obtain the Bitcoin address used to sign the message - 驗證一則訊息, 並獲知用來簽署該訊息的位元幣位址 - - - - &Verify Message - 驗證訊息 - - - - Copy the currently selected address to the system clipboard - 複製目前選取的位址到系統剪貼簿 - - - - &Copy Address - 複製位址 - - - - Reset all verify message fields - 重置所有訊息驗證欄位 - - - - Clear &All - 全部清掉 - - - - Enter Bitcoin signature - 輸入位元幣簽章 - - - - Click "Verify Message" to obtain address - 按"驗證訊息"來取得位址 - - - - - Invalid Signature - 無效的簽章 - - - - The signature could not be decoded. Please check the signature and try again. - 無法將這個簽章解碼. 請檢查簽章是否正確後再試一次. - - - - The signature did not match the message digest. Please check the signature and try again. - 簽章與訊息的數位摘要不符. 請檢查簽章是否正確後再試一次. - - - - Address not found in address book. - 在位址簿中找不到該位址. - - - - Address found in address book: %1 - 在位址簿中找到此位址: %1 - - WalletModel - - Sending... - 付出中... + + Send Coins + 付錢 - WindowOptionsPage + WalletView - - Window - 視窗 + + &Export + 匯出 - - &Minimize to the tray instead of the taskbar - 最小化至通知區域而非工作列 + + Export the data in the current tab to a file + 將目前分頁的資料匯出存成檔案 - - Show only a tray icon after minimizing the window - 視窗最小化時只顯示圖示於通知區域 + + Backup Wallet + 錢包備份 - - M&inimize on close - 關閉時最小化 + + Wallet Data (*.dat) + 錢包資料檔 (*.dat) - - Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - 當視窗關閉時將其最小化, 而非結束應用程式. 當勾選這個選項時, 應用程式只能用選單中的結束來停止執行. + + Backup Failed + 備份失敗 + + + + There was an error trying to save the wallet data to the new location. + 儲存錢包資料到新的地方失敗 + + + + Backup Successful + 備份成功 + + + + The wallet data was successfully saved to the new location. + 錢包的資料已經成功儲存到新的地方了. bitcoin-core - - Bitcoin version - 位元幣版本 + + CasinoCoin version + 莱特幣版本 - + Usage: 用法: - - Send command to -server or bitcoind - 送指令至 -server 或 bitcoind + + Send command to -server or casinocoind + 送指令給 -server 或 casinocoind - + List commands 列出指令 - + Get help for a command 取得指令說明 - + Options: 選項: - - Specify configuration file (default: bitcoin.conf) - 指定設定檔 (預設: bitcoin.conf) + + Specify configuration file (default: casinocoin.conf) + 指定設定檔 (預設: casinocoin.conf) - - Specify pid file (default: bitcoind.pid) - 指定行程識別碼檔案 (預設: bitcoind.pid) + + Specify pid file (default: casinocoind.pid) + 指定行程識別碼檔案 (預設: casinocoind.pid) - - Generate coins - 生產位元幣 - - - - - Don't generate coins - 不生產位元幣 - - - - + Specify data directory 指定資料目錄 - + Set database cache size in megabytes (default: 25) 設定資料庫快取大小為多少百萬位元組(MB, 預設: 25) - - Set database disk log size in megabytes (default: 100) - 設定資料庫的磁碟紀錄大小為多少百萬位元組(MB, 預設: 100) + + Listen for connections on <port> (default: 47950 or testnet: 17950) + 在通訊埠 <port> 聽候連線 (預設: 47950, 或若為測試網路: 17950) - - Specify connection timeout (in milliseconds) - 指定連線逾時時間 (毫秒) - - - - - Listen for connections on <port> (default: 8333 or testnet: 18333) - 在通訊埠 <port> 聽候連線 (預設: 8333, 或若為測試網路: 18333) - - - + Maintain at most <n> connections to peers (default: 125) 維持與節點連線數的上限為 <n> 個 (預設: 125) - - Connect only to the specified node - 只連線至指定節點 - - - - + Connect to a node to retrieve peer addresses, and disconnect 連線到某個節點以取得其它節點的位址, 然後斷線 - + Specify your own public address 指定自己公開的位址 - - Only connect to nodes in network <net> (IPv4 or IPv6) - 只和 <net> 網路上的節點連線 (IPv4 或 IPv6) - - - - Try to discover public IP address (default: 1) - 試著找出公開的網際網路位址 (預設: 1) - - - - Bind to given address. Use [host]:port notation for IPv6 - 與指定的位址繫結. IPv6 要使用 [主機]:通訊埠 的格式 - - - + Threshold for disconnecting misbehaving peers (default: 100) 與亂搞的節點斷線的臨界值 (預設: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) 避免與亂搞的節點連線的秒數 (預設: 86400) - - Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000) - 每個連線的接收緩衝區大小上限為 <n>*1000 位元組 (預設: 10000) + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + 在 IPv4 網路上以通訊埠 %u 聽取 RPC 連線時發生錯誤: %s - - Maximum per-connection send buffer, <n>*1000 bytes (default: 10000) - 每個連線的傳送緩衝區大小上限為 <n>*1000 位元組 (預設: 10000) + + Listen for JSON-RPC connections on <port> (default: 47970 or testnet: 17970) + 在通訊埠 <port> 聽候 JSON-RPC 連線 (預設: 47970, 或若為測試網路: 17970) - - Detach block and address databases. Increases shutdown time (default: 0) - 卸載區塊與位址的資料庫. 會延長關閉時間 (預設: 0) - - - + Accept command line and JSON-RPC commands 接受命令列與 JSON-RPC 指令 - + Run in the background as a daemon and accept commands 以背景程式執行並接受指令 - + Use the test network 使用測試網路 - - Output extra debugging information - 輸出額外的除錯資訊 + + Accept connections from outside (default: 1 if no -proxy or -connect) + 是否接受外來連線 (預設: 當沒有 -proxy 或 -connect 時預設為 1) - + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=casinocoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + %s, 你必須要在以下設定檔中設定 RPC 密碼(rpcpassword): +%s +建議你使用以下隨機產生的密碼: +rpcuser=casinocoinrpc +rpcpassword=%s +(你不用記住這個密碼) +使用者名稱(rpcuser)和密碼(rpcpassword)不可以相同! +如果設定檔還不存在, 請在新增時, 設定檔案權限為"只有主人才能讀取". +也建議你設定警示通知, 發生問題時你才會被通知到; +比如說設定為: +alertnotify=echo %%s | mail -s "CasinoCoin Alert" admin@foo.com + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + 設定在 IPv6 網路的通訊埠 %u 上聽候 RPC 連線失敗, 退而改用 IPv4 網路: %s + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + 和指定的位址繫結, 並總是在該位址聽候連線. IPv6 請用 "[主機]:通訊埠" 這種格式 + + + + Cannot obtain a lock on data directory %s. CasinoCoin is probably already running. + 無法鎖定資料目錄 %s. 也許莱特幣已經在執行了. + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + 錯誤: 交易被拒絕了! 有時候會發生這種錯誤, 是因為你錢包中的一些錢已經被花掉了. 比如說你複製了錢包檔 wallet.dat, 然後用複製的錢包花掉了錢, 你現在所用的原來的錢包中卻沒有該筆交易紀錄. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + 錯誤: 這筆交易需要至少 %s 的手續費! 因為它的金額太大, 或複雜度太高, 或是使用了最近才剛收到的款項. + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + 當收到相關警示時所要執行的指令 (指令中的 %s 會被取代為警示訊息) + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + 當錢包有交易改變時所要執行的指令 (指令中的 %s 會被取代為交易識別碼) + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + 設定高優先權或低手續費的交易資料大小上限為多少位元組 (預設: 27000) + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + 這是尚未發表的測試版本 - 使用請自負風險 - 請不要用於開採或商業應用 + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + 警告: -paytxfee 設定了很高的金額! 這可是你交易付款所要付的手續費. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + 警告: 顯示的交易可能不正確! 你可能需要升級, 或者需要等其它的節點升級. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly. + 警告: 請檢查電腦時間與日期是否正確! 莱特幣無法在時鐘不準的情況下正常運作. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + 警告: 讀取錢包檔 wallet.dat 失敗了! 所有的密鑰都正確讀取了, 但是交易資料或位址簿資料可能會缺少或不正確. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + 警告: 錢包檔 wallet.dat 壞掉, 但資料被拯救回來了! 原來的 wallet.dat 會改儲存在 %s, 檔名為 wallet.{timestamp}.bak. 如果餘額或交易資料有誤, 你應該要用備份資料復原回來. + + + + Attempt to recover private keys from a corrupt wallet.dat + 嘗試從壞掉的錢包檔 wallet.dat 復原密鑰 + + + + Block creation options: + 區塊產生選項: + + + + Connect only to the specified node(s) + 只連線至指定節點(可多個) + + + + Corrupted block database detected + 發現區塊資料庫壞掉了 + + + + Discover own IP address (default: 1 when listening and no -externalip) + 找出自己的網際網路位址 (預設: 當有聽候連線且沒有 -externalip 時為 1) + + + + Do you want to rebuild the block database now? + 你要現在重建區塊資料庫嗎? + + + + Error initializing block database + 初始化區塊資料庫失敗 + + + + Error initializing wallet database environment %s! + 錢包資料庫環境 %s 初始化錯誤! + + + + Error loading block database + 載入區塊資料庫失敗 + + + + Error opening block database + 打開區塊資料庫檔案失敗 + + + + Error: Disk space is low! + 錯誤: 磁碟空間很少! + + + + Error: Wallet locked, unable to create transaction! + 錯誤: 錢包被上鎖了, 無法產生新的交易! + + + + Error: system error: + 錯誤: 系統錯誤: + + + + Failed to listen on any port. Use -listen=0 if you want this. + 在任意的通訊埠聽候失敗. 如果你想的話可以用 -listen=0. + + + + Failed to read block info + 讀取區塊資訊失敗 + + + + Failed to read block + 讀取區塊失敗 + + + + Failed to sync block index + 同步區塊索引失敗 + + + + Failed to write block index + 寫入區塊索引失敗 + + + + Failed to write block info + 寫入區塊資訊失敗 + + + + Failed to write block + 寫入區塊失敗 + + + + Failed to write file info + 寫入檔案資訊失敗 + + + + Failed to write to coin database + 寫入莱特幣資料庫失敗 + + + + Failed to write transaction index + 寫入交易索引失敗 + + + + Failed to write undo data + 寫入回復資料失敗 + + + + Find peers using DNS lookup (default: 1 unless -connect) + 是否允許在找節點時使用域名查詢 (預設: 當沒用 -connect 時為 1) + + + + Generate coins (default: 0) + 生產莱特幣 (預設值: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) + 啓動時檢查的區塊數 (預設: 288, 指定 0 表示全部) + + + + How thorough the block verification is (0-4, default: 3) + 區塊檢查的仔細程度 (0 至 4, 預設: 3) + + + + Not enough file descriptors available. + 檔案描述器不足. + + + + Rebuild block chain index from current blk000??.dat files + 從目前的區塊檔 blk000??.dat 重建鎖鏈索引 + + + + Set the number of threads to service RPC calls (default: 4) + 設定處理 RPC 服務請求的執行緒數目 (預設為 4) + + + + Verifying blocks... + 驗證區塊資料中... + + + + Verifying wallet... + 驗證錢包資料中... + + + + Imports blocks from external blk000??.dat file + 從其它來源的 blk000??.dat 檔匯入區塊 + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + 設定指令碼驗證的執行緒數目 (最多為 16, 若為 0 表示程式自動決定, 小於 0 表示保留不用的處理器核心數目, 預設為 0) + + + + Information + 資訊 + + + + Invalid -tor address: '%s' + 無效的 -tor 位址: '%s' + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + 設定 -minrelaytxfee=<金額> 的金額無效: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + 設定 -mintxfee=<amount> 的金額無效: '%s' + + + + Maintain a full transaction index (default: 0) + 維護全部交易的索引 (預設為 0) + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + 每個連線的接收緩衝區大小上限為 <n>*1000 個位元組 (預設: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + 每個連線的傳送緩衝區大小上限為 <n>*1000 位元組 (預設: 1000) + + + + Only accept block chain matching built-in checkpoints (default: 1) + 只接受與內建的檢查段點吻合的區塊鎖鏈 (預設: 1) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + 只和 <net> 網路上的節點連線 (IPv4, IPv6, 或 Tor) + + + + Output extra debugging information. Implies all other -debug* options + 輸出額外的除錯資訊. 包含了其它所有的 -debug* 選項 + + + + Output extra network debugging information + 輸出額外的網路除錯資訊 + + + Prepend debug output with timestamp 在除錯輸出內容前附加時間 - - Send trace/debug info to console instead of debug.log file - 輸出追蹤或除錯資訊至終端機, 而非 debug.log 檔案 + + SSL options: (see the CasinoCoin Wiki for SSL setup instructions) + SSL 選項: (SSL 設定程序請見 CasinoCoin Wiki) - + + Select the version of socks proxy to use (4-5, default: 5) + 選擇 SOCKS 代理伺服器的協定版本(4 或 5, 預設: 5) + + + + Send trace/debug info to console instead of debug.log file + 在終端機顯示追蹤或除錯資訊, 而非寫到 debug.log 檔 + + + Send trace/debug info to debugger 輸出追蹤或除錯資訊給除錯器 - + + Set maximum block size in bytes (default: 250000) + 設定區塊大小上限為多少位元組 (預設: 250000) + + + + Set minimum block size in bytes (default: 0) + 設定區塊大小下限為多少位元組 (預設: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + 客戶端軟體啓動時將 debug.log 檔縮小 (預設: 當沒有 -debug 時為 1) + + + + Signing transaction failed + 簽署交易失敗 + + + + Specify connection timeout in milliseconds (default: 5000) + 指定連線在幾毫秒後逾時 (預設: 5000) + + + + System error: + 系統錯誤: + + + + Transaction amount too small + 交易金額太小 + + + + Transaction amounts must be positive + 交易金額必須是正的 + + + + Transaction too large + 交易位元量太大 + + + + Use UPnP to map the listening port (default: 0) + 是否使用通用即插即用(UPnP)協定來設定聽候連線的通訊埠 (預設: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + 是否使用通用即插即用(UPnP)協定來設定聽候連線的通訊埠 (預設: 當有聽候連線為 1) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + 透過代理伺服器來使用 Tor 隱藏服務 (預設: 同 -proxy) + + + Username for JSON-RPC connections JSON-RPC 連線使用者名稱 - + + Warning + 警告 + + + + Warning: This version is obsolete, upgrade required! + 警告: 這個版本已經被淘汰掉了, 必須要升級! + + + + You need to rebuild the databases using -reindex to change -txindex + 改變 -txindex 參數後, 必須要用 -reindex 參數來重建資料庫 + + + + wallet.dat corrupt, salvage failed + 錢包檔 weallet.dat 壞掉了, 拯救失敗 + + + Password for JSON-RPC connections JSON-RPC 連線密碼 - - Listen for JSON-RPC connections on <port> (default: 8332) - 在通訊埠 <port> 聽候 JSON-RPC 連線 (預設: 8332) - - - + Allow JSON-RPC connections from specified IP address 只允許從指定網路位址來的 JSON-RPC 連線 - + Send commands to node running on <ip> (default: 127.0.0.1) 送指令給在 <ip> 的節點 (預設: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) 當最新區塊改變時所要執行的指令 (指令中的 %s 會被取代為區塊的雜湊值) - + Upgrade wallet to latest format 將錢包升級成最新的格式 - + Set key pool size to <n> (default: 100) 設定密鑰池大小為 <n> (預設: 100) - + Rescan the block chain for missing wallet transactions 重新掃描區塊鎖鏈, 以尋找錢包所遺漏的交易. - - How many blocks to check at startup (default: 2500, 0 = all) - 啓動時檢查多少區塊 (預設: 2500, 0 表示全部) - - - - How thorough the block verification is (0-6, default: 1) - 區塊檢查的仔細程度 (0 至 6, 預設: 1) - - - - Imports blocks from external blk000?.dat file - 從外來的區塊檔 blk000?.dat 匯入區塊 - - - - -SSL options: (see the Bitcoin Wiki for SSL setup instructions) - -SSL 選項: (SSL 設定程序請見 Bitcoin Wiki) - - - - + Use OpenSSL (https) for JSON-RPC connections - 使用 OpenSSL (https) 於JSON-RPC 連線 + 於 JSON-RPC 連線使用 OpenSSL (https) - + Server certificate file (default: server.cert) 伺服器憑證檔 (預設: server.cert) - + Server private key (default: server.pem) 伺服器密鑰檔 (預設: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) 可以接受的加密法 (預設: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - - Warning: Disk space is low - 警告: 磁碟空間很少 - - - + This help message 此協助訊息 - - Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - 無法鎖定資料目錄 %s. 也許位元幣已經在執行了. - - - - Bitcoin - 位元幣 - - - + Unable to bind to %s on this computer (bind returned error %d, %s) 無法和這台電腦上的 %s 繫結 (繫結回傳錯誤 %d, %s) - + Connect through socks proxy 透過 SOCKS 代理伺服器連線 - - Select the version of socks proxy to use (4 or 5, 5 is default) - 選擇 SOCKS 代理伺服器的協定版本(4 或 5, 預設是 5) - - - - Do not use proxy for connections to network <net> (IPv4 or IPv6) - 不透過 SOCKS 代理伺服器連線至 <net> 網路 (IPv4 或 IPv6) - - - + Allow DNS lookups for -addnode, -seednode and -connect 允許對 -addnode, -seednode, -connect 的參數使用域名查詢 - - Pass DNS requests to (SOCKS5) proxy - 透過 (SOCKS5) 代理伺服器送出域名查詢 - - - + Loading addresses... 載入位址中... - - Error loading blkindex.dat - 載入 blkindex.dat 失敗 - - - + Error loading wallet.dat: Wallet corrupted 載入檔案 wallet.dat 失敗: 錢包壞掉了 - - Error loading wallet.dat: Wallet requires newer version of Bitcoin - 載入檔案 wallet.dat 失敗: 此錢包需要新版的 Bitcoin + + Error loading wallet.dat: Wallet requires newer version of CasinoCoin + 載入檔案 wallet.dat 失敗: 此錢包需要新版的 CasinoCoin - - Wallet needed to be rewritten: restart Bitcoin to complete - 錢包需要重寫: 請重啟位元幣來完成 + + Wallet needed to be rewritten: restart CasinoCoin to complete + 錢包需要重寫: 請重啟莱特幣來完成 - + Error loading wallet.dat 載入檔案 wallet.dat 失敗 - + Invalid -proxy address: '%s' 無效的 -proxy 位址: '%s' - - Unknown network specified in -noproxy: '%s' - 在 -noproxy 指定了不明的網路別: '%s' - - - + Unknown network specified in -onlynet: '%s' 在 -onlynet 指定了不明的網路別: '%s' - + Unknown -socks proxy version requested: %i 在 -socks 指定了不明的代理協定版本: %i - + Cannot resolve -bind address: '%s' 無法解析 -bind 位址: '%s' - - Not listening on any port - 不在任何通訊埠聽候連線 - - - + Cannot resolve -externalip address: '%s' 無法解析 -externalip 位址: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' 設定 -paytxfee=<金額> 的金額無效: '%s' - - Error: could not start node - 錯誤: 無法啓動節點 - - - - Error: Wallet locked, unable to create transaction - 錯誤: 錢包被上鎖了, 無法產生新的交易 - - - - Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds - 錯誤: 這筆交易需要至少 %s 的手續費, 因為它的金額太大, 或複雜度太高, 或是使用了最近才剛收到的款項 - - - - Error: Transaction creation failed - 錯誤: 交易產生失敗 - - - - Sending... - 付出中... - - - - Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - 錯誤: 交易被拒絕. 有時候會發生這種錯誤, 是因為你錢包中的一些錢已經被花掉了. 比如說你複製了錢包檔 wallet.dat, 然後用複製的錢包花掉了錢, 你現在所用的原來的錢包中卻沒有該筆交易紀錄. - - - + Invalid amount 無效的金額 - + Insufficient funds 累積金額不足 - + Loading block index... 載入區塊索引中... - + Add a node to connect to and attempt to keep the connection open 加入一個要連線的節線, 並試著保持對它的連線暢通 - - Unable to bind to %s on this computer. Bitcoin is probably already running. - 無法和這台電腦上的 %s 繫結. 也許位元幣已經在執行了. + + Unable to bind to %s on this computer. CasinoCoin is probably already running. + 無法和這台電腦上的 %s 繫結. 也許莱特幣已經在執行了. - - Find peers using internet relay chat (default: 0) - 是否使用網際網路中繼聊天(IRC)來找節點 (預設: 0) - - - - Accept connections from outside (default: 1) - 是否接受外來連線 (預設: 1) - - - - Find peers using DNS lookup (default: 1) - 是否允許在找節點時使用域名查詢 (預設: 1) - - - - Use Universal Plug and Play to map the listening port (default: 1) - 是否使用通用即插即用(UPnP)來設定聽候連線的通訊埠 (預設: 1) - - - - Use Universal Plug and Play to map the listening port (default: 0) - 是否使用通用即插即用(UPnP)來設定聽候連線的通訊埠 (預設: 0) - - - + Fee per KB to add to transactions you send 交易付款時每 KB 的交易手續費 - - Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction. - 警告: -paytxfee 設定了很高的金額. 這可是你交易付款所要付的手續費. - - - + Loading wallet... 載入錢包中... - + Cannot downgrade wallet 無法將錢包格式降級 - - Cannot initialize keypool - 無法將密鑰池初始化 - - - + Cannot write default address 無法寫入預設位址 - + Rescanning... 重新掃描中... - + Done loading 載入完成 - + To use the %s option 為了要使用 %s 選項 - - %s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. - - %s, 你必須在下列設定檔中設定 RPC 密碼(rpcpassword): -%s -建議你使用下列的隨機產生密碼: -rpcuser=bitcoinrpc -rpcpassword=%s -(你不用記住這個密碼) -如果這個檔案還不存在, 請在新增時設定檔案權限為只有擁有者才能讀取. - - - - + Error 錯誤 - - An error occured while setting up the RPC port %i for listening: %s - 設定聽候 RPC 連線的通訊埠 %i 時發生錯誤: %s - - - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. 你必須在下列設定檔中設定 RPC 密碼(rpcpassword=<password>): %s -如果這個檔案還不存在, 請在新增時設定檔案權限為只有擁有者才能讀取. - - - - Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly. - 警告: 請檢查電腦時間日期是否正確. 位元幣無法在時鐘不準的情況下正常運作. +如果這個檔案還不存在, 請在新增時, 設定檔案權限為"只有主人才能讀取". \ No newline at end of file diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h index b5ccfed..765b004 100644 --- a/src/qt/macdockiconhandler.h +++ b/src/qt/macdockiconhandler.h @@ -1,12 +1,14 @@ #ifndef MACDOCKICONHANDLER_H #define MACDOCKICONHANDLER_H -#include +#include +#include +QT_BEGIN_NAMESPACE class QMenu; class QIcon; class QWidget; -class objc_object; +QT_END_NAMESPACE #ifdef __OBJC__ @class DockIconClickEventHandler; @@ -19,12 +21,13 @@ class DockIconClickEventHandler; class MacDockIconHandler : public QObject { Q_OBJECT + public: ~MacDockIconHandler(); QMenu *dockMenu(); void setIcon(const QIcon &icon); - + void setMainWindow(QMainWindow *window); static MacDockIconHandler *instance(); void handleDockIconClickEvent(); @@ -32,14 +35,13 @@ public: signals: void dockIconClicked(); -public slots: - private: MacDockIconHandler(); DockIconClickEventHandler *m_dockIconClickEventHandler; QWidget *m_dummyWidget; QMenu *m_dockMenu; + QMainWindow *mainWindow; }; #endif // MACDOCKICONCLICKHANDLER_H diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index df56e69..86b8c83 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -1,14 +1,17 @@ - #include "macdockiconhandler.h" -#include -#include - -extern void qt_mac_set_dock_menu(QMenu*); +#include +#include +#include +#include #undef slots #include +#if QT_VERSION < 0x050000 +extern void qt_mac_set_dock_menu(QMenu *); +#endif + @interface DockIconClickEventHandler : NSObject { MacDockIconHandler* dockIconHandler; @@ -38,8 +41,9 @@ extern void qt_mac_set_dock_menu(QMenu*); Q_UNUSED(event) Q_UNUSED(replyEvent) - if (dockIconHandler) + if (dockIconHandler) { dockIconHandler->handleDockIconClickEvent(); + } } @end @@ -47,18 +51,26 @@ extern void qt_mac_set_dock_menu(QMenu*); MacDockIconHandler::MacDockIconHandler() : QObject() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; + this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; this->m_dummyWidget = new QWidget(); this->m_dockMenu = new QMenu(this->m_dummyWidget); + this->setMainWindow(NULL); +#if QT_VERSION < 0x050000 qt_mac_set_dock_menu(this->m_dockMenu); +#endif [pool release]; } +void MacDockIconHandler::setMainWindow(QMainWindow *window) { + this->mainWindow = window; +} + MacDockIconHandler::~MacDockIconHandler() { [this->m_dockIconClickEventHandler release]; delete this->m_dummyWidget; + this->setMainWindow(NULL); } QMenu *MacDockIconHandler::dockMenu() @@ -69,15 +81,29 @@ QMenu *MacDockIconHandler::dockMenu() void MacDockIconHandler::setIcon(const QIcon &icon) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSImage *image; + NSImage *image = nil; if (icon.isNull()) image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; else { + // generate NSImage from QIcon and use this as dock icon. QSize size = icon.actualSize(QSize(128, 128)); QPixmap pixmap = icon.pixmap(size); - CGImageRef cgImage = pixmap.toMacCGImageRef(); - image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; - CFRelease(cgImage); + + // write temp file hack (could also be done through QIODevice [memory]) + QTemporaryFile notificationIconFile; + if (!pixmap.isNull() && notificationIconFile.open()) { + QImageWriter writer(¬ificationIconFile, "PNG"); + if (writer.write(pixmap.toImage())) { + const char *cString = notificationIconFile.fileName().toUtf8().data(); + NSString *macString = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding]; + image = [[NSImage alloc] initWithContentsOfFile:macString]; + } + } + + if(!image) { + // if testnet image could not be created, load std. app icon + image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; + } } [NSApp setApplicationIconImage:image]; @@ -95,5 +121,11 @@ MacDockIconHandler *MacDockIconHandler::instance() void MacDockIconHandler::handleDockIconClickEvent() { + if (this->mainWindow) + { + this->mainWindow->activateWindow(); + this->mainWindow->show(); + } + emit this->dockIconClicked(); } diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h new file mode 100644 index 0000000..cd8064c --- /dev/null +++ b/src/qt/macnotificationhandler.h @@ -0,0 +1,25 @@ +#ifndef MACNOTIFICATIONHANDLER_H +#define MACNOTIFICATIONHANDLER_H +#include + +/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl). + */ +class MacNotificationHandler : public QObject +{ + Q_OBJECT + +public: + /** shows a 10.8+ UserNotification in the UserNotificationCenter + */ + void showNotification(const QString &title, const QString &text); + + /** executes AppleScript */ + void sendAppleScript(const QString &script); + + /** check if OS can handle UserNotifications */ + bool hasUserNotificationCenterSupport(void); + static MacNotificationHandler *instance(); +}; + + +#endif // MACNOTIFICATIONHANDLER_H diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm new file mode 100644 index 0000000..8bb9b88 --- /dev/null +++ b/src/qt/macnotificationhandler.mm @@ -0,0 +1,65 @@ +#include "macnotificationhandler.h" + +#undef slots +#include + +void MacNotificationHandler::showNotification(const QString &title, const QString &text) +{ + // check if users OS has support for NSUserNotification + if(this->hasUserNotificationCenterSupport()) { + // okay, seems like 10.8+ + QByteArray utf8 = title.toUtf8(); + char* cString = (char *)utf8.constData(); + NSString *titleMac = [[NSString alloc] initWithUTF8String:cString]; + + utf8 = text.toUtf8(); + cString = (char *)utf8.constData(); + NSString *textMac = [[NSString alloc] initWithUTF8String:cString]; + + // do everything weak linked (because we will keep <10.8 compatibility) + id userNotification = [[NSClassFromString(@"NSUserNotification") alloc] init]; + [userNotification performSelector:@selector(setTitle:) withObject:titleMac]; + [userNotification performSelector:@selector(setInformativeText:) withObject:textMac]; + + id notificationCenterInstance = [NSClassFromString(@"NSUserNotificationCenter") performSelector:@selector(defaultUserNotificationCenter)]; + [notificationCenterInstance performSelector:@selector(deliverNotification:) withObject:userNotification]; + + [titleMac release]; + [textMac release]; + [userNotification release]; + } +} + +// sendAppleScript just take a QString and executes it as apple script +void MacNotificationHandler::sendAppleScript(const QString &script) +{ + QByteArray utf8 = script.toUtf8(); + char* cString = (char *)utf8.constData(); + NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString]; + + NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple]; + NSDictionary *err = nil; + [as executeAndReturnError:&err]; + [as release]; + [scriptApple release]; +} + +bool MacNotificationHandler::hasUserNotificationCenterSupport(void) +{ + Class possibleClass = NSClassFromString(@"NSUserNotificationCenter"); + + // check if users OS has support for NSUserNotification + if(possibleClass!=nil) { + return true; + } + return false; +} + + +MacNotificationHandler *MacNotificationHandler::instance() +{ + static MacNotificationHandler *s_instance = NULL; + if (!s_instance) + s_instance = new MacNotificationHandler(); + return s_instance; +} diff --git a/src/qt/monitoreddatamapper.cpp b/src/qt/monitoreddatamapper.cpp index 88948d0..4c20183 100644 --- a/src/qt/monitoreddatamapper.cpp +++ b/src/qt/monitoreddatamapper.cpp @@ -9,7 +9,6 @@ MonitoredDataMapper::MonitoredDataMapper(QObject *parent) : { } - void MonitoredDataMapper::addMapping(QWidget *widget, int section) { QDataWidgetMapper::addMapping(widget, section); diff --git a/src/qt/monitoreddatamapper.h b/src/qt/monitoreddatamapper.h index 33a874e..de55c86 100644 --- a/src/qt/monitoreddatamapper.h +++ b/src/qt/monitoreddatamapper.h @@ -13,19 +13,18 @@ QT_END_NAMESPACE class MonitoredDataMapper : public QDataWidgetMapper { Q_OBJECT + public: explicit MonitoredDataMapper(QObject *parent=0); void addMapping(QWidget *widget, int section); void addMapping(QWidget *widget, int section, const QByteArray &propertyName); + private: void addChangeMonitor(QWidget *widget); signals: void viewModified(); - }; - - #endif // MONITOREDDATAMAPPER_H diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index e668079..7cfaef6 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -12,13 +12,13 @@ #include #ifdef USE_DBUS -#include +#include #include #endif -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC #include -extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); +#include "macnotificationhandler.h" #endif // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128 @@ -46,20 +46,26 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, mode = Freedesktop; } #endif -#ifdef Q_WS_MAC - // Check if Growl is installed (based on Qt's tray icon implementation) - CFURLRef cfurl; - OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); - if (status != kLSApplicationNotFoundErr) { - CFBundleRef bundle = CFBundleCreate(0, cfurl); - if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { - if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) - mode = Growl13; - else - mode = Growl12; +#ifdef Q_OS_MAC + // check if users OS has support for NSUserNotification + if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) { + mode = UserNotificationCenter; + } + else { + // Check if Growl is installed (based on Qt's tray icon implementation) + CFURLRef cfurl; + OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); + if (status != kLSApplicationNotFoundErr) { + CFBundleRef bundle = CFBundleCreate(0, cfurl); + if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { + if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) + mode = Growl13; + else + mode = Growl12; + } + CFRelease(cfurl); + CFRelease(bundle); } - CFRelease(cfurl); - CFRelease(bundle); } #endif } @@ -82,7 +88,7 @@ public: static int metaType(); - // Image to variant that can be marshaled over DBus + // Image to variant that can be marshalled over DBus static QVariant toVariant(const QImage &img); private: @@ -113,7 +119,7 @@ FreedesktopImage::FreedesktopImage(const QImage &img): { // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format QImage tmp = img.convertToFormat(QImage::Format_ARGB32); - const uint32_t *data = reinterpret_cast(tmp.constBits()); + const uint32_t *data = reinterpret_cast(tmp.bits()); unsigned int num_pixels = width * height; image.resize(num_pixels * BYTES_PER_PIXEL); @@ -225,7 +231,7 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString & } // Based on Qt's tray icon implementation -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon) { const QString script( @@ -269,8 +275,14 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te quotedTitle.replace("\\", "\\\\").replace("\"", "\\"); quotedText.replace("\\", "\\\\").replace("\"", "\\"); QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp"); - qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0); + MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp)); } + +void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) { + // icon is not supported by the user notification center yet. OSX will use the app icon. + MacNotificationHandler::instance()->showNotification(title, text); +} + #endif void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) @@ -285,7 +297,10 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c case QSystemTray: notifySystray(cls, title, text, icon, millisTimeout); break; -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC + case UserNotificationCenter: + notifyMacUserNotificationCenter(cls, title, text, icon); + break; case Growl12: case Growl13: notifyGrowl(cls, title, text, icon); @@ -294,7 +309,7 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c default: if(cls == Critical) { - // Fall back to old fashioned popup dialog if critical and no other notification available + // Fall back to old fashioned pop-up dialog if critical and no other notification available QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok); } break; diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 0271c26..d1fe37f 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -15,6 +15,7 @@ QT_END_NAMESPACE class Notificator: public QObject { Q_OBJECT + public: /** Create a new notificator. @note Ownership of trayIcon is not transferred to this object. @@ -25,13 +26,12 @@ public: // Message class enum Class { - Information, /**< Informational message */ - Warning, /**< Notify user of potential problem */ - Critical /**< An error occured */ + Information, /**< Informational message */ + Warning, /**< Notify user of potential problem */ + Critical /**< An error occurred */ }; public slots: - /** Show notification message. @param[in] cls general message class @param[in] title title shown with message @@ -46,11 +46,12 @@ public slots: private: QWidget *parent; enum Mode { - None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ - Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ - Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ - Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ + None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ + Freedesktop, /**< Use DBus org.freedesktop.Notifications */ + QSystemTray, /**< Use QSystemTray::showMessage */ + Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ + Growl13, /**< Use the Growl 1.3 notification system (Mac only) */ + UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; Mode mode; @@ -61,8 +62,9 @@ private: void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon); + void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon); #endif }; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index da93671..6cb141c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -1,26 +1,15 @@ #include "optionsdialog.h" #include "ui_optionsdialog.h" -#include "bitcoinamountfield.h" #include "bitcoinunits.h" #include "monitoreddatamapper.h" #include "netbase.h" #include "optionsmodel.h" -#include "qvalidatedlineedit.h" -#include "qvaluecombobox.h" -#include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include OptionsDialog::OptionsDialog(QWidget *parent) : QDialog(parent), @@ -38,24 +27,26 @@ OptionsDialog::OptionsDialog(QWidget *parent) : ui->mapPortUpnp->setEnabled(false); #endif + ui->proxyIp->setEnabled(false); + ui->proxyPort->setEnabled(false); + ui->proxyPort->setValidator(new QIntValidator(1, 65535, this)); + ui->socksVersion->setEnabled(false); ui->socksVersion->addItem("5", 5); ui->socksVersion->addItem("4", 4); ui->socksVersion->setCurrentIndex(0); - ui->proxyIp->setEnabled(false); - ui->proxyPort->setEnabled(false); - ui->proxyPort->setValidator(new QIntValidator(0, 65535, this)); - - connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool))); connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool))); connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool))); + connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool))); + connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy())); ui->proxyIp->installEventFilter(this); /* Window elements init */ -#ifdef Q_WS_MAC - ui->tabWindow->setVisible(false); +#ifdef Q_OS_MAC + /* remove Window tab on Mac */ + ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow)); #endif /* Display elements init */ @@ -90,20 +81,17 @@ OptionsDialog::OptionsDialog(QWidget *parent) : ui->unit->setModel(new BitcoinUnits(this)); - connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy())); - connect(ui->lang, SIGNAL(activated(int)), this, SLOT(showRestartWarning_Lang())); - /* Widget-to-option mapper */ mapper = new MonitoredDataMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); mapper->setOrientation(Qt::Vertical); - /* enable save buttons when data modified */ - connect(mapper, SIGNAL(viewModified()), this, SLOT(enableSaveButtons())); - /* disable save buttons when new data loaded */ - connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableSaveButtons())); - /* disable/enable save buttons when proxy IP is invalid/valid */ - connect(this, SIGNAL(proxyIpValid(bool)), this, SLOT(setSaveButtonState(bool))); + /* enable apply button when data modified */ + connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApplyButton())); + /* disable apply button when new data loaded */ + connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton())); + /* setup/change UI elements when proxy IP is invalid/valid */ + connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool))); } OptionsDialog::~OptionsDialog() @@ -124,8 +112,14 @@ void OptionsDialog::setModel(OptionsModel *model) mapper->toFirst(); } - // update the display unit, to not use the default ("BTC") + /* update the display unit, to not use the default ("BTC") */ updateDisplayUnit(); + + /* warn only when language selection changes by user action (placed here so init via mapper doesn't trigger this) */ + connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning_Lang())); + + /* disable apply button after settings are loaded as there is nothing to save */ + disableApplyButton(); } void OptionsDialog::setMapper() @@ -133,17 +127,17 @@ void OptionsDialog::setMapper() /* Main */ mapper->addMapping(ui->transactionFee, OptionsModel::Fee); mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup); - mapper->addMapping(ui->detachDatabases, OptionsModel::DetachDatabases); /* Network */ mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP); + mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse); - mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion); mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP); mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort); + mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion); /* Window */ -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose); #endif @@ -152,11 +146,22 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->lang, OptionsModel::Language); mapper->addMapping(ui->unit, OptionsModel::DisplayUnit); mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses); + mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); +} + +void OptionsDialog::enableApplyButton() +{ + ui->applyButton->setEnabled(true); +} + +void OptionsDialog::disableApplyButton() +{ + ui->applyButton->setEnabled(false); } void OptionsDialog::enableSaveButtons() { - // prevent enabling of the save buttons when data modified, if there is an invalid proxy address present + /* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */ if(fProxyIpValid) setSaveButtonState(true); } @@ -172,6 +177,33 @@ void OptionsDialog::setSaveButtonState(bool fState) ui->okButton->setEnabled(fState); } +void OptionsDialog::on_resetButton_clicked() +{ + if(model) + { + // confirmation dialog + QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"), + tr("Some settings may require a client restart to take effect.") + "

" + tr("Do you want to proceed?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + + if(btnRetVal == QMessageBox::Cancel) + return; + + disableApplyButton(); + + /* disable restart warning messages display */ + fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = true; + + /* reset all options and save the default values (QSettings) */ + model->Reset(); + mapper->toFirst(); + mapper->submit(); + + /* re-enable restart warning messages display */ + fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = false; + } +} + void OptionsDialog::on_okButton_clicked() { mapper->submit(); @@ -186,7 +218,7 @@ void OptionsDialog::on_cancelButton_clicked() void OptionsDialog::on_applyButton_clicked() { mapper->submit(); - ui->applyButton->setEnabled(false); + disableApplyButton(); } void OptionsDialog::showRestartWarning_Proxy() @@ -211,30 +243,39 @@ void OptionsDialog::updateDisplayUnit() { if(model) { - // Update transactionFee with the current unit + /* Update transactionFee with the current unit */ ui->transactionFee->setDisplayUnit(model->getDisplayUnit()); } } +void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState) +{ + // this is used in a check before re-enabling the save buttons + fProxyIpValid = fState; + + if(fProxyIpValid) + { + enableSaveButtons(); + ui->statusLabel->clear(); + } + else + { + disableSaveButtons(); + object->setValid(fProxyIpValid); + ui->statusLabel->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel->setText(tr("The supplied proxy address is invalid.")); + } +} + bool OptionsDialog::eventFilter(QObject *object, QEvent *event) { - if(object == ui->proxyIp && event->type() == QEvent::FocusOut) + if(event->type() == QEvent::FocusOut) { - // Check proxyIP for a valid IPv4/IPv6 address - CService addr; - if(!LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr)) + if(object == ui->proxyIp) { - ui->proxyIp->setValid(false); - fProxyIpValid = false; - ui->statusLabel->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel->setText(tr("The supplied proxy address is invalid.")); - emit proxyIpValid(false); - } - else - { - fProxyIpValid = true; - ui->statusLabel->clear(); - emit proxyIpValid(true); + CService addr; + /* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */ + emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr)); } } return QDialog::eventFilter(object, event); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 7e91c96..d64ed0b 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -8,6 +8,7 @@ class OptionsDialog; } class OptionsModel; class MonitoredDataMapper; +class QValidatedLineEdit; /** Preferences dialog. */ class OptionsDialog : public QDialog @@ -25,12 +26,17 @@ protected: bool eventFilter(QObject *object, QEvent *event); private slots: + /* enable only apply button */ + void enableApplyButton(); + /* disable only apply button */ + void disableApplyButton(); /* enable apply button and OK button */ void enableSaveButtons(); /* disable apply button and OK button */ void disableSaveButtons(); /* set apply button and OK button state (enabled / disabled) */ void setSaveButtonState(bool fState); + void on_resetButton_clicked(); void on_okButton_clicked(); void on_cancelButton_clicked(); void on_applyButton_clicked(); @@ -38,9 +44,10 @@ private slots: void showRestartWarning_Proxy(); void showRestartWarning_Lang(); void updateDisplayUnit(); + void handleProxyIpValid(QValidatedLineEdit *object, bool fState); signals: - void proxyIpValid(bool fValid); + void proxyIpValid(QValidatedLineEdit *object, bool fValid); private: Ui::OptionsDialog *ui; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index caa3341..4f60f96 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1,11 +1,12 @@ #include "optionsmodel.h" -#include "bitcoinunits.h" -#include +#include "bitcoinunits.h" #include "init.h" #include "walletdb.h" #include "guiutil.h" +#include + OptionsModel::OptionsModel(QObject *parent) : QAbstractListModel(parent) { @@ -47,6 +48,7 @@ void OptionsModel::Init() fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool(); nTransactionFee = settings.value("nTransactionFee").toLongLong(); language = settings.value("language", "").toString(); + fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool(); // These are shared with core Bitcoin; we want // command-line options to override the GUI settings: @@ -56,12 +58,28 @@ void OptionsModel::Init() SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()); if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool()) SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString()); - if (settings.contains("detachDB")) - SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool()); if (!language.isEmpty()) SoftSetArg("-lang", language.toStdString()); } +void OptionsModel::Reset() +{ + QSettings settings; + + // Remove all entries in this QSettings object + settings.clear(); + + // default setting for OptionsModel::StartAtStartup - disabled + if (GUIUtil::GetStartOnSystemStartup()) + GUIUtil::SetStartOnSystemStartup(false); + + // Re-Init to get default values + Init(); + + // Ensure Upgrade() is not running again by setting the bImportFinished flag + settings.setValue("bImportFinished", true); +} + bool OptionsModel::Upgrade() { QSettings settings; @@ -139,43 +157,55 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const case MinimizeToTray: return QVariant(fMinimizeToTray); case MapPortUPnP: +#ifdef USE_UPNP return settings.value("fUseUPnP", GetBoolArg("-upnp", true)); +#else + return QVariant(false); +#endif case MinimizeOnClose: return QVariant(fMinimizeOnClose); - case ProxyUse: - return settings.value("fUseProxy", false); + case ProxyUse: { + proxyType proxy; + return QVariant(GetProxy(NET_IPV4, proxy)); + } case ProxyIP: { - CService addrProxy; - if (GetProxy(NET_IPV4, addrProxy)) - return QVariant(QString::fromStdString(addrProxy.ToStringIP())); + proxyType proxy; + if (GetProxy(NET_IPV4, proxy)) + return QVariant(QString::fromStdString(proxy.first.ToStringIP())); else return QVariant(QString::fromStdString("127.0.0.1")); } case ProxyPort: { - CService addrProxy; - if (GetProxy(NET_IPV4, addrProxy)) - return QVariant(addrProxy.GetPort()); + proxyType proxy; + if (GetProxy(NET_IPV4, proxy)) + return QVariant(proxy.first.GetPort()); else - return 9050; + return QVariant(9050); + } + case ProxySocksVersion: { + proxyType proxy; + if (GetProxy(NET_IPV4, proxy)) + return QVariant(proxy.second); + else + return QVariant(5); } - case ProxySocksVersion: - return settings.value("nSocksVersion", 5); case Fee: return QVariant(nTransactionFee); case DisplayUnit: return QVariant(nDisplayUnit); case DisplayAddresses: return QVariant(bDisplayAddresses); - case DetachDatabases: - return QVariant(bitdb.GetDetach()); case Language: return settings.value("language", ""); + case CoinControlFeatures: + return QVariant(fCoinControlFeatures); default: return QVariant(); } } return QVariant(); } + bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role) { bool successful = true; /* set to false on parse error */ @@ -192,9 +222,8 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in settings.setValue("fMinimizeToTray", fMinimizeToTray); break; case MapPortUPnP: - fUseUPnP = value.toBool(); - settings.setValue("fUseUPnP", fUseUPnP); - MapPort(); + settings.setValue("fUseUPnP", value.toBool()); + MapPort(value.toBool()); break; case MinimizeOnClose: fMinimizeOnClose = value.toBool(); @@ -202,34 +231,43 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in break; case ProxyUse: settings.setValue("fUseProxy", value.toBool()); - ApplyProxySettings(); - break; - case ProxyIP: - { - CService addrProxy("127.0.0.1", 9050); - GetProxy(NET_IPV4, addrProxy); - CNetAddr addr(value.toString().toStdString()); - addrProxy.SetIP(addr); - settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); - successful = ApplyProxySettings(); - } - break; - case ProxyPort: - { - CService addrProxy("127.0.0.1", 9050); - GetProxy(NET_IPV4, addrProxy); - addrProxy.SetPort(value.toInt()); - settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); - successful = ApplyProxySettings(); - } - break; - case ProxySocksVersion: - settings.setValue("nSocksVersion", value.toInt()); - ApplyProxySettings(); + successful = ApplyProxySettings(); break; + case ProxyIP: { + proxyType proxy; + proxy.first = CService("127.0.0.1", 9050); + GetProxy(NET_IPV4, proxy); + + CNetAddr addr(value.toString().toStdString()); + proxy.first.SetIP(addr); + settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str()); + successful = ApplyProxySettings(); + } + break; + case ProxyPort: { + proxyType proxy; + proxy.first = CService("127.0.0.1", 9050); + GetProxy(NET_IPV4, proxy); + + proxy.first.SetPort(value.toInt()); + settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str()); + successful = ApplyProxySettings(); + } + break; + case ProxySocksVersion: { + proxyType proxy; + proxy.second = 5; + GetProxy(NET_IPV4, proxy); + + proxy.second = value.toInt(); + settings.setValue("nSocksVersion", proxy.second); + successful = ApplyProxySettings(); + } + break; case Fee: nTransactionFee = value.toLongLong(); settings.setValue("nTransactionFee", nTransactionFee); + emit transactionFeeChanged(nTransactionFee); break; case DisplayUnit: nDisplayUnit = value.toInt(); @@ -240,15 +278,15 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in bDisplayAddresses = value.toBool(); settings.setValue("bDisplayAddresses", bDisplayAddresses); break; - case DetachDatabases: { - bool fDetachDB = value.toBool(); - bitdb.SetDetach(fDetachDB); - settings.setValue("detachDB", fDetachDB); - } - break; case Language: settings.setValue("language", value); break; + case CoinControlFeatures: { + fCoinControlFeatures = value.toBool(); + settings.setValue("fCoinControlFeatures", fCoinControlFeatures); + emit coinControlFeaturesChanged(fCoinControlFeatures); + } + break; default: break; } @@ -263,22 +301,8 @@ qint64 OptionsModel::getTransactionFee() return nTransactionFee; } -bool OptionsModel::getMinimizeToTray() +bool OptionsModel::getCoinControlFeatures() { - return fMinimizeToTray; + return fCoinControlFeatures; } -bool OptionsModel::getMinimizeOnClose() -{ - return fMinimizeOnClose; -} - -int OptionsModel::getDisplayUnit() -{ - return nDisplayUnit; -} - -bool OptionsModel::getDisplayAddresses() -{ - return bDisplayAddresses; -} diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 34724ad..be94c1a 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -28,12 +28,13 @@ public: Fee, // qint64 DisplayUnit, // BitcoinUnits::Unit DisplayAddresses, // bool - DetachDatabases, // bool Language, // QString + CoinControlFeatures, // bool OptionIDRowCount, }; void Init(); + void Reset(); /* Migrate settings from wallet.dat after app initialization */ bool Upgrade(); /* returns true if settings upgraded */ @@ -44,11 +45,12 @@ public: /* Explicit getters */ qint64 getTransactionFee(); - bool getMinimizeToTray(); - bool getMinimizeOnClose(); - int getDisplayUnit(); - bool getDisplayAddresses(); + bool getMinimizeToTray() { return fMinimizeToTray; } + bool getMinimizeOnClose() { return fMinimizeOnClose; } + int getDisplayUnit() { return nDisplayUnit; } + bool getDisplayAddresses() { return bDisplayAddresses; } QString getLanguage() { return language; } + bool getCoinControlFeatures(); private: int nDisplayUnit; @@ -56,9 +58,12 @@ private: bool fMinimizeToTray; bool fMinimizeOnClose; QString language; + bool fCoinControlFeatures; signals: void displayUnitChanged(int unit); + void transactionFeeChanged(qint64); + void coinControlFeaturesChanged(bool); }; #endif // OPTIONSMODEL_H diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index aa93bda..ad2d682 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -1,6 +1,7 @@ #include "overviewpage.h" #include "ui_overviewpage.h" +#include "clientmodel.h" #include "walletmodel.h" #include "bitcoinunits.h" #include "optionsmodel.h" @@ -45,9 +46,10 @@ public: bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool(); QVariant value = index.data(Qt::ForegroundRole); QColor foreground = option.palette.color(QPalette::Text); - if(qVariantCanConvert(value)) + if(value.canConvert()) { - foreground = qvariant_cast(value); + QBrush brush = qvariant_cast(value); + foreground = brush.color(); } painter->setPen(foreground); @@ -92,6 +94,8 @@ public: OverviewPage::OverviewPage(QWidget *parent) : QWidget(parent), ui(new Ui::OverviewPage), + clientModel(0), + walletModel(0), currentBalance(-1), currentUnconfirmedBalance(-1), currentImmatureBalance(-1), @@ -109,8 +113,8 @@ OverviewPage::OverviewPage(QWidget *parent) : connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex))); // init "out of sync" warning labels - ui->labelWalletStatus->setText("(" + tr("Out of sync") + ")"); - ui->labelTransactionsStatus->setText("(" + tr("Out of sync") + ")"); + ui->labelWalletStatus->setText("(" + tr("out of sync") + ")"); + ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")"); // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); @@ -129,7 +133,7 @@ OverviewPage::~OverviewPage() void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance) { - int unit = model->getOptionsModel()->getDisplayUnit(); + int unit = walletModel->getOptionsModel()->getDisplayUnit(); currentBalance = balance; currentUnconfirmedBalance = unconfirmedBalance; currentImmatureBalance = immatureBalance; @@ -144,14 +148,20 @@ void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 ui->labelImmatureText->setVisible(showImmature); } -void OverviewPage::setNumTransactions(int count) +void OverviewPage::setClientModel(ClientModel *model) { - ui->labelNumTransactions->setText(QLocale::system().toString(count)); + this->clientModel = model; + if(model) + { + // Show warning if this is a prerelease version + connect(model, SIGNAL(alertsChanged(QString)), this, SLOT(updateAlerts(QString))); + updateAlerts(model->getStatusBarWarnings()); + } } -void OverviewPage::setModel(WalletModel *model) +void OverviewPage::setWalletModel(WalletModel *model) { - this->model = model; + this->walletModel = model; if(model && model->getOptionsModel()) { // Set up transaction list @@ -169,30 +179,33 @@ void OverviewPage::setModel(WalletModel *model) setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance()); connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64))); - setNumTransactions(model->getNumTransactions()); - connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); } - // update the display unit, to not use the default ("CSC") + // update the display unit, to not use the default ("BTC") updateDisplayUnit(); } void OverviewPage::updateDisplayUnit() { - if(model && model->getOptionsModel()) + if(walletModel && walletModel->getOptionsModel()) { if(currentBalance != -1) setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance); // Update txdelegate->unit with the current unit - txdelegate->unit = model->getOptionsModel()->getDisplayUnit(); + txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit(); ui->listTransactions->update(); } } +void OverviewPage::updateAlerts(const QString &warnings) +{ + this->ui->labelAlerts->setVisible(!warnings.isEmpty()); + this->ui->labelAlerts->setText(warnings); +} + void OverviewPage::showOutOfSyncWarning(bool fShow) { ui->labelWalletStatus->setVisible(fShow); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 00048cc..59ba3c6 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -3,17 +3,18 @@ #include -QT_BEGIN_NAMESPACE -class QModelIndex; -QT_END_NAMESPACE - namespace Ui { class OverviewPage; } +class ClientModel; class WalletModel; class TxViewDelegate; class TransactionFilterProxy; +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + /** Overview ("home") page widget */ class OverviewPage : public QWidget { @@ -23,19 +24,20 @@ public: explicit OverviewPage(QWidget *parent = 0); ~OverviewPage(); - void setModel(WalletModel *model); + void setClientModel(ClientModel *clientModel); + void setWalletModel(WalletModel *walletModel); void showOutOfSyncWarning(bool fShow); public slots: void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance); - void setNumTransactions(int count); signals: void transactionClicked(const QModelIndex &index); private: Ui::OverviewPage *ui; - WalletModel *model; + ClientModel *clientModel; + WalletModel *walletModel; qint64 currentBalance; qint64 currentUnconfirmedBalance; qint64 currentImmatureBalance; @@ -46,6 +48,7 @@ private: private slots: void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex &index); + void updateAlerts(const QString &warnings); }; #endif // OVERVIEWPAGE_H diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp new file mode 100644 index 0000000..3514664 --- /dev/null +++ b/src/qt/paymentserver.cpp @@ -0,0 +1,162 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include "paymentserver.h" + +#include "guiconstants.h" +#include "ui_interface.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#if QT_VERSION < 0x050000 +#include +#endif + +using namespace boost; + +const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds +const QString BITCOIN_IPC_PREFIX("casinocoin:"); + +// +// Create a name that is unique for: +// testnet / non-testnet +// data directory +// +static QString ipcServerName() +{ + QString name("BitcoinQt"); + + // Append a simple hash of the datadir + // Note that GetDataDir(true) returns a different path + // for -testnet versus main net + QString ddir(GetDataDir(true).string().c_str()); + name.append(QString::number(qHash(ddir))); + + return name; +} + +// +// This stores payment requests received before +// the main GUI window is up and ready to ask the user +// to send payment. +// +static QStringList savedPaymentRequests; + +// +// Sending to the server is done synchronously, at startup. +// If the server isn't already running, startup continues, +// and the items in savedPaymentRequest will be handled +// when uiReady() is called. +// +bool PaymentServer::ipcSendCommandLine() +{ + bool fResult = false; + + const QStringList& args = qApp->arguments(); + for (int i = 1; i < args.size(); i++) + { + if (!args[i].startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) + continue; + savedPaymentRequests.append(args[i]); + } + + foreach (const QString& arg, savedPaymentRequests) + { + QLocalSocket* socket = new QLocalSocket(); + socket->connectToServer(ipcServerName(), QIODevice::WriteOnly); + if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT)) + return false; + + QByteArray block; + QDataStream out(&block, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_4_0); + out << arg; + out.device()->seek(0); + socket->write(block); + socket->flush(); + + socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT); + socket->disconnectFromServer(); + delete socket; + fResult = true; + } + return fResult; +} + +PaymentServer::PaymentServer(QApplication* parent) : QObject(parent), saveURIs(true) +{ + // Install global event filter to catch QFileOpenEvents on the mac (sent when you click bitcoin: links) + parent->installEventFilter(this); + + QString name = ipcServerName(); + + // Clean up old socket leftover from a crash: + QLocalServer::removeServer(name); + + uriServer = new QLocalServer(this); + + if (!uriServer->listen(name)) + qDebug() << tr("Cannot start casinocoin: click-to-pay handler"); + else + connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection())); +} + +bool PaymentServer::eventFilter(QObject *object, QEvent *event) +{ + // clicking on bitcoin: URLs creates FileOpen events on the Mac: + if (event->type() == QEvent::FileOpen) + { + QFileOpenEvent* fileEvent = static_cast(event); + if (!fileEvent->url().isEmpty()) + { + if (saveURIs) // Before main window is ready: + savedPaymentRequests.append(fileEvent->url().toString()); + else + emit receivedURI(fileEvent->url().toString()); + return true; + } + } + return false; +} + +void PaymentServer::uiReady() +{ + saveURIs = false; + foreach (const QString& s, savedPaymentRequests) + emit receivedURI(s); + savedPaymentRequests.clear(); +} + +void PaymentServer::handleURIConnection() +{ + QLocalSocket *clientConnection = uriServer->nextPendingConnection(); + + while (clientConnection->bytesAvailable() < (int)sizeof(quint32)) + clientConnection->waitForReadyRead(); + + connect(clientConnection, SIGNAL(disconnected()), + clientConnection, SLOT(deleteLater())); + + QDataStream in(clientConnection); + in.setVersion(QDataStream::Qt_4_0); + if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) { + return; + } + QString message; + in >> message; + + if (saveURIs) + savedPaymentRequests.append(message); + else + emit receivedURI(message); +} diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h new file mode 100644 index 0000000..1f2fdd4 --- /dev/null +++ b/src/qt/paymentserver.h @@ -0,0 +1,67 @@ +#ifndef PAYMENTSERVER_H +#define PAYMENTSERVER_H + +// +// This class handles payment requests from clicking on +// bitcoin: URIs +// +// This is somewhat tricky, because we have to deal with +// the situation where the user clicks on a link during +// startup/initialization, when the splash-screen is up +// but the main window (and the Send Coins tab) is not. +// +// So, the strategy is: +// +// Create the server, and register the event handler, +// when the application is created. Save any URIs +// received at or during startup in a list. +// +// When startup is finished and the main window is +// show, a signal is sent to slot uiReady(), which +// emits a receivedURL() signal for any payment +// requests that happened during startup. +// +// After startup, receivedURL() happens as usual. +// +// This class has one more feature: a static +// method that finds URIs passed in the command line +// and, if a server is running in another process, +// sends them to the server. +// +#include +#include + +class QApplication; +class QLocalServer; + +class PaymentServer : public QObject +{ + Q_OBJECT + +private: + bool saveURIs; + QLocalServer* uriServer; + +public: + // Returns true if there were URIs on the command line + // which were successfully sent to an already-running + // process. + static bool ipcSendCommandLine(); + + PaymentServer(QApplication* parent); + + bool eventFilter(QObject *object, QEvent *event); + +signals: + void receivedURI(QString); + +public slots: + // Signal this when the main window's UI is ready + // to display payment requests to the user + void uiReady(); + +private slots: + void handleURIConnection(); +}; + +#endif // PAYMENTSERVER_H diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp index e1c8beb..c4b26c3 100644 --- a/src/qt/qrcodedialog.cpp +++ b/src/qt/qrcodedialog.cpp @@ -7,7 +7,9 @@ #include "optionsmodel.h" #include +#if QT_VERSION < 0x050000 #include +#endif #include diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index 66e26be..ec74633 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -9,6 +9,7 @@ class QValidatedLineEdit : public QLineEdit { Q_OBJECT + public: explicit QValidatedLineEdit(QWidget *parent = 0); void clear(); diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index 1a47bb6..64a7da9 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -8,7 +8,9 @@ class QValueComboBox : public QComboBox { Q_OBJECT + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged USER true) + public: explicit QValueComboBox(QWidget *parent = 0); @@ -21,8 +23,6 @@ public: signals: void valueChanged(); -public slots: - private: int role; diff --git a/src/qt/res/bitcoin-qt.rc b/src/qt/res/bitcoin-qt.rc index 1a1ab53..aed420f 100644 --- a/src/qt/res/bitcoin-qt.rc +++ b/src/qt/res/bitcoin-qt.rc @@ -1 +1,39 @@ IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico" +IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico" + +#include // needed for VERSIONINFO +#include "../../clientversion.h" // holds the needed client version information + +#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD) +#define VER_FILEVERSION VER_PRODUCTVERSION +#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR +#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin developers 2011-" STRINGIZE(COPYRIGHT_YEAR) " The CasinoCoin developers" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "CasinoCoin" + VALUE "FileDescription", "CasinoCoin-Qt (OSS GUI client for CasinoCoin)" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "casinocoin-qt" + VALUE "LegalCopyright", COPYRIGHT_STR + VALUE "LegalTrademarks1", "Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php." + VALUE "OriginalFilename", "casinocoin-qt.exe" + VALUE "ProductName", "CasinoCoin-Qt" + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/src/qt/res/icons/bitcoin_testnet.ico b/src/qt/res/icons/bitcoin_testnet.ico new file mode 100644 index 0000000000000000000000000000000000000000..0ac200ca54f2d32481fc6b83700cf8ad525ba84c GIT binary patch literal 370070 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%0AP2IF6{sl>%Ey!oWxXMFhqNOa*%B!q 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 literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/casinocoin.icns b/src/qt/res/icons/casinocoin.icns new file mode 100644 index 0000000000000000000000000000000000000000..943813b4d89bca7cc7130514a773f9c530520b62 GIT binary patch literal 104142 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 UDx>yK3mYF?%&3~Z3;u5W4@8v7$N&HU literal 0 HcmV?d00001 diff --git a/src/qt/res/images/splash.png b/src/qt/res/images/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..696fa85795e808caf7420a4fc7bf8da393e7b0fc GIT binary patch literal 246711 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

TU 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�eaxMYHCU^O?@PpdCpN=_r+MmAwSNe39777MR9)q5mkXA(uP85y=WLu#KOEV|PRPncEjDXb% zR7Fy?O_DHG*&j<}3QginctrwM^&s(|COy~p>wm$c?k+-Rdg>F=>G4=vCf1$u2E-i< z4l4CtPcXLq_3`E#8$ji|ZSQ^3jmj@=byyzG)2_B#Z+g1%dw6=#``+K>dE?Go^iftQ z-}XqZ@jeXStI=Y=-r`nU+I`+IagRlkv*Es?=W#)80$FC>I1TxkVC;SUg~+&RR>%Q^-Yk)Y8tG!6ZZJS)*llfu?pEI4*uX-J|0}A|4f3WD)bs^E#C3AD;qU_C< z`1LpZL(o@7gPtEx*9Y_(|K}L=sCjfA*7aOq8p7UM}U#B3NkNXnPwmdmN<^FlA0JAV1R z8KV%6BqK?s5h5p8$xFx0Vn%m%l2Ls{qlufw%bt49BttJlPk?q7Z+B^@HU{N??;xb6 z`W2(x+Po*pD+|xQs`d$~6P`=WAMPPp}`p+6BIiOe4= zet=7>?If_mRI-3#a2P5^X|Z;VtJ{0vs;`ChGXsIw0sXo;G$WtYqnbs`w)@L^?+5(4 zT8OZA_0Q5=_xarSG5wjpgQrV7kIyUJ57FW#9D5Y4Jzj4e$05^>s~+z zIyn#Dg9%QbkCzt&;Ecl{cb~7i*ZkJr^#7iFihbqV{w_2$bgG{FT3?@F#s1-N%tQB; z&&;X}1k)bnc-xN~*n7dlH#PxgPEaO7H|;C z?ku}Q$8p6l!ayp|z{oI@k2yX8A zckj_<(h3#Ocs?WW&~9Vj?e^ox4}(ZQY?t=E2znG47w$fHH7KX~>4}stybv2aRG0nV z(PpsQm_v{B_4VbT9j)8c%Kg;*<#G6apCI!U7au=!%A;cGG^gGK;!evWv>>7O`e5Sd zont6ltx}z@vT&OFC<_9Bf2;Pv?Afl?0RbT)At{Uo{13G**JISNQBeevm>W6_=+NGe z;j-?QhhLgt`q&b*7!XID%a`-{(%X?JGsF;jDDJ)@1PqVvjZ?ni75n}0GXK_s2yF(Z z#sC|D6(=N?uv}L_N=9c0BNkV~2yH~c$_(xwgb`JvnG{t`+(Cd!Kso55d9c+^ldG_2 zG_8tKkzOEW3xZLEF1TE!)}Cj~N<6i!Fi+@8D+nM57E;s)5!wY{4t3BOnA^r>>{{mu z{swXia%Oz*8@+R0Az&*ra`9X2=ALWImg5e@ zgECUmHU^k*OiuZH`3oLy6~qm zFR)s~N0S?!#YB^9kc7n#qZ10Y6ea01gpy2w0rpoV@=+`)BWOZl`y;?$SBQpcd{fh` zx3%V|=Ah(JI~9!^qxq8TZ`)8BEBP73!UV9WDMYq542B8WO2GmH;`2Y{d*)5nL!;Nx zaMW;+8htx8^$!P|BMI{UG#FW39QDVX%?qvx-RBoaPdPbTG1)l8AF1@Uria?q(xU#7 zlAbwgbjf35W8PQ2ei!S_Udw;)QcN3#=?W_cp!nHl5i=(8P~@pL-vN($mx5 zx~7jf_s-Q{CXFX;maEb;=X71?#2{4LF2n_MalT$){exI+Cj@AZ3=e0J}H&JFv zUJ-o63Z&-tUT%l!7DS-7M)<=FW*O2ZdwQZLsM`L;RYe9aSQEPI2v+nzlE2v!P+@Sy zeAJzr+M0T=N~o!Od?s8CqGPp^h+F%JIR<6mZ(zHz!q%-fT5z##@$>Q%4a)*Sl;H?L z%o&DcQurC=xHQGJdgdsBRM{$ER_W#lV6zwkD}dcia#>{kEZkYyRW4qAv1HtpHj!B# zaZ-{&)ULG9tMuHtQQDuDgi>MfPvPMdi?Atz^#Zee%7u9pFI2S5TGW_y`&m*~W7tB> zs9k~%HHFz~dF^&U3-3-@AR2UD`J~b&JT#lNs^uC}ZXJ{NuF%tU&>17nI9+?LG~u|ksRHex(XI35d`R-Eiya~vbyL?jG1Rb}e$CYvTo`BDk7m+8RL$~}>{><*%a zWGCO@`HgHSW{VtUlSgfgvn0?(Zn`qAWsVu!- zNcI;_SVfvB3=oJ0yM~0EIO{x)H7T1ouLq;Z9EmoE)V}wFxWUZ4s6P+Oj%VC;);;M{ zP&yc4Zg4>g;ot9Y!a|vDnxT`jLQ;7vNbttpmz_;wL!*=o>zEC5PfxAc7vZ39wg?V^ zGpnySw9E^1!e+@A5}B#yXXW*(l6z+D$GcT4_|d0oiO^jJG{zLy}}PkPhDN-3Vv=|Ot=3F4@bu5*mQf~6Xks~`+W++DFrOV)VA$Kyj?j$Nb?!- z=zxHL#hHu^{~ZC`BMAELh5V0lO%jR$|50J*`}5g@!OP?_%gkvRgig=#JWQwMD_5_a zcz86qNSQwWz|d@WKCqpYvf%AQd9KkZStfFzE8rBA%fT#wqnZOk0vd@d3f5^ATLb{P zP!UroiyBr$&Xxz-zaF>EPR?^9g9E^DJe7+2L=Lw(FV3&(BobXkV^p9g4^0CDtpX#2 zcwA(1ke6p}T|u?nj;Iagka%c77YYzULqZecna|4poL6GVfq@MEQjqRhvb#AmgS8|* zt4yD$lp&-$gyzp0q-NKz<0#6r;+@1pm7LqYF)gHFcPQUr8F{0Tac-$R?jx(WY zMtzD2jSD0V6k)1sV66_I0_%>9hJ>#s7+p8cxX0k+^j@BQ6fKSaJt-xAjXV-~jE`() z@c6_-ij;esumu`7)ABu_Hz-%D6w}&ha65xoVb^s{XN%od1#{kwH!>&TY0^Wz<;Qd= z|Br=e&NlAf)8(Z(&x{|}j4xUr5LC5+s$(&g!5&V2lL(&;!!!ezVK$L61)KJuu$vz3 z-x!+vKk+fQ25ry{xjpsDW}|_SHBHvk>j#2Bd8jmtnHCM_Syoe?J*;)h#jgd{U&*M# zZA%KyalyfBKne+3Oj;!-o;-h)^y1UDrTWlJmklb}ul)8KruB9eZ3nc*!MjBKRV&2H zeV5*ktm@WK^|nwo|z|BGXRH136Jym(zZAS8rBEg=Dqgj`V6n8nm}`DCm4Mtk>hlDp1Vul-5pkvz}9KK7@lQr+~$L8zUqG1h7{85^Vc%DbgscL8IDZ8eB$J- zl{~s?zuGR%_4T@ZebBe)XY9V6hj>m0fv&Xnp%q9}bcV1^**^DcGdP&O3D_?IN#9*e zmV40CEt&~Om0Sh}S%;G>?#^e7OxdLB(#l<8MEl5SE8Qh&vE}-s=56!xNWEr%7hqTj zX|4+@CBVbF{YHclmM-EivCJ4|my>IiKTVP9B$Sqz3i2{^A{Qu2nVQjaI7BN0TVpM= z^}}3i(kWm9H0$L)K}=Fi2>>TTP5}*r4Vm4n3N2$iXqa(%)41#rWosS~y;Pu0dPtO! zb`sTUViB<@>t6V{N|0idAOyokCjFEK1d&#-f>*W9!IM0Pz+!XXp|ye#-lo!)y2I3a ziy*9(GupsrF^-s4F6f!*crxMPkP2O|aZF|w?nopQJtM&3tQ^L7O7^@(T9`wW-S{pQ zaj66-YvW^_V1J(!YZ0iQfAA5(XrL(DUb)*G@t`mthuU;G{=XzVtvbpgqD!zh9=xX+ zXEi~hkbO@FPmO1`V65t86`Pf5WVV~5nVqv~i(H?3vs68f&m&ti?vO**a~`97>DTq; z*a#3EJM!5;_5N$oOB*~Wa#oH9bJ%C+W*Zn$L1#RF(i}$>t7k@1T097sz)~Tj_w!F? zpg+Kr5JWNdE7L7`OobOoP-wUOlQu6mG>0C!{%qoxs^=%}smeC-L#b*)6O8I}yf|1@ zhq9DG@j3rEFp`v<)}UZK036NJz-tnoVgaWi1u3DlqU-uuJX62>G z1H>;9@L;GF{ze`J=bI@Cu^TbdQ$o`?lPilN31{JH7L|mV{?T(amlW<33^t4b2)(>? zxrtwa>Vtv`=UC_6!^#og(JtA4fai!}YYkfMQG`Ei9fCmS8?9F?OD7MculyVw_lUiJ z5kG0Jtr+KIs{arF;FV4JjxHdCiq|lL&E=VHqxsbA?5ytSEB9}5c<05%s=A3{O_nCz zgR0zJ1rT=JFWm9Vd@(1(wl>|8+kbLlFX~W(ZUFMK$~avrW|5R>;O=eFWXJmY%Jawo zc;cbKmNX>Um?Pi-*uZ?|I+?!DC_L5b!Ng>Cx#T9{nJW3L+Fo6fNB)#m zfLqT49F(P?Wd)I|($E)cRaA$^0PE$yvL!-x4TSLlt5H6J+Wd&3OtB7a8p-g1QkVD?5YR(1c2F z8~=ztA_-ArQl4v&&Z-tKZ5JNnynd>k*w(}UYo>MCYq&O}yc13T+C`1$GEw}$yZ8{Y z;7r(sbPs1AJ=sFr3`JnUQOx&r*^Ow>{x0Qq;e7F7;FMFl){ zNx~*cpMTV38Sk;&AIPmY*v7p???4HQBKZUvLgi7IT`Qaw(Fkt(~2*za%Ru!?S9B^9HE zxDAym*Yks(y2O*4(1AWxR4dI|us_(sO4uFJMZnGk;Y(<=I!fb#`so6i%!M@v>Y}0) z>347&D=lt6&T$uARCRPbh@*I}?2ewlT_wzTTquMO76AM;n;xvK&_zZon@wW*%rAok z!Vf1PXU*5@eb)t_-M)GQ`&qXxcPxqxnwe7@f_BaAySN~k>I1tKWWD3fjDWz;*mlP& zRwDL^1*y4H0loz^QC1xugIFBbg)f5jErFlX0A)kyCX!^HaABh5aY_{QlT52ECA>yb z`;5N6{i)maf5|P7v%K1JHN*glE`S)O!kAAL{!$+QB1kg@sSgB)V2d0K)!>x^l!skY z3bFdxQbEy>M*^ZwW?W)`3X&QGgA2_lS@6h>n{fJ7(-0(-?NqOep}ibyiETDC{JuSB z8tf>w)af(tDkt)rz#j&hIvPwdJSYi$Ycz3&3Dyp7a~wsn8Tz>ZA7a zJ@%N!@mfMl{^=$XX-?!1RK8huyPVW>NsAFkmRfP|r)*~?s~cnirlGB`CcIGV2;gPD zZ{LrdNthF5(oq#M3HRRkoV(nju#%|Skc&BLlH}1)hw7`zxu5t0aPn;$1djn8dUDHF zEL!kmmzIvk!Pw48#DHr?Im-j3$zWaKWqC7llLJ?R|VaE`DV}Rf<`DQqAkRg=# z=z2b1C0Rp293BZRw1h-Wl_^uL($p%4Try{^)ponOdUb9(&D!MG*Y@#pneSd0ECHl( zxRe0=(a8!FFPowJF$P#=vAbh1!^Cc|$nO>j01uD#G*Z~??ERHcqpvX;F~O=rV>XL` z*UlTZ8E3||g}_aEPzurQK&9Vz2u#AR#wPiq+jN|iXz=Xa`{2#F^?jjvMfWYV_v5Aa zd7}6AC*zNQ_q^)z(Xr5ig{@b`)Y%Xrr)OWo_bK(^Psq0;N0)xs&y!R3zIe(35EcAi zYwz2|n#JpVYp)MPzMk+ugCN9{J|u4mLB_xTX5B*gp2fvJ<6Ti0e3@kOjpx%G zLquy88>Jh>VbBg2UFHFh0Jd@>rKa-E$Yz;7QK!{7>G!;t#=!`k3#gS@?v^H7ZB^UL zy3O3*8r;lvFn~yu0Fpq?>O#_<>{?xJoNTN0Uz7ov+~hnSUe} zH*__-?K?`*S^o4$(11cwQ@}+adk6^1*j!Y;Fb$Wbz56Sr+!*%dt%oBOw=myLB+ID@ z(RlkWt0qLm1wvz@AY62`fP6d>Iw7eftxw`1x&>&KaFeG2qeX1;dl+-+Mr>16Oy@v? z%jSwo+iaSe4KAmZ;pHIw$bTI802Uk&$xeOA-Lr}_8L^}m5F@jX1lNIUdE0A~UynM* z7{OG2X;n_H9V3R~B_PO@CHf?KoprBEVMcZ(m0>LvA_O|-#PUDRLS~a7_c*5V+7-?{ zu1b8&jPO7E5kX3S+|E{3Y?=#W`Mth>#{s-Q?h|u1ZrFePlkj~QaPZ#PSgz6QG@rtQ z<~pAhd7u-)F!}K(UgF+);Kw~&X1Li+7h?hBR`(zoX|9gug*e`3<6b5&UA^^E1tbxj zmUB!99OPe^LB^j4Ej99;a@U3W(WRqsv2)%0RF^fLmHaiQZTMA=aPXIG6d`^d9%&iR zh*Gqkzhs3rPnf3kFvyO6$gt!VgOyqQE|~gjO}8tsCbz1FuzAE|5MIJue7%CIT%7sb zbr6iqFm2A?NEn488wtv|JZXH^F$U}xB<6RQu(4Qv=S({g*}n5$aU34m~Z&)~W$DTpn1V_R7m}r(zKtOpqE)SLoKoEljD9p?u zf=Zz%6iFi;w#@=XRccHLVD`6S1GCp~tr)~d+>k48ceQx#v@GxI>`N|?$XUe4mDq-? zop-?R?&XCYe*x41A#<~6 zVFs{b7!90@JWMw(P1EeqAM&{Xv&0oHoZqs)!_n)af-fJ9K7NsMRZp%cG_6DpF6|rb zy8>86ITE$p2}ujXsc0xaQTe-hFB1Ne3-z{)gKHL)5~7~qqU>m~;xcv z%jNYaL1#$GgBp(LpRCiFaQnm5;X?yA*v>i756L#2|{oyQ2w5Al*3hR$< z!PtK#Pa6p438d+3<;xRj>zDU2BUqaZG{sa(Cdf#UB}hJNzg^NvTyVRm1Ttq>1LHJq z&X45Fw>y0au#|9kR7_@O*@>f__CxO87{B+oY-l)}T}9z*R8~JNx5mEh^y;sPgxSno zbe#D%8NKnCdhE+_+O5{@3Ok{|A)(!A9n7!K6mG} z9j6r#CMgS2F8Q+e*rHv1R@>{#sd$JR8|Z`T_stw;S7 zr5q;r#*^T5GGNZO8DSDm}k|qvZ^o? zw&V{`y62JP!9;-&Xu^Vr&8Z^7tiuSGdjH6fA7?4CAl?#=2u>pr?i&ta?92ASx2B@T z%JOqB=Y)-UBZg0^q6r1`kB*AM0;1`e9E6;m zgUuSdscLpqX=r5H_1OOTX~y7SxWvC52G$Am4_EsT>hGwYNB1dK?dFgDsTTyEKe{dp zC2l*N*0uJmopv9$Qx1W+yqx?z*V%qgsXMRHJF6e>ty}IJ5J@dM_s_V(^WaPw#`BLQ zEe&0#AqXUm`z}KJTr?LNe0`q#uM6V;AX-@VkL$7jS@sTBs|a$dFw$LiZ#lL94J~rH zjTT&i9v~*`?vaP?b@n$#I8sl3Dnj;14o`I}45`FC@gWqs9Z z#$;BekuCJc_$(*`GAx5ah(}TlPev$C5o1+}3$nS48}6g+=a6Mz;dGl4_4e+J3M-Ej zhK55|lib%857z&ZQG9ERQYnr`qh+BL8knc1cJKHeY8ob3QbYgIaRa{C~Z-7<-K=#_erY9Ft!!W5fT zKT@Z;gKplhS##TO9zMX6_h#>vq<=(2YTved?=N4da#MDkMrv2PJXyUN^S@n}6<+GL zH&~#`MP-xL(rkZBd+5JsU-f<1ejsz2IwHga26(rD{OqsWiVnK zVlGOy#&AJ(tmv??7G&7WimJaW=9j0YEy)WNEp@)27BB-qVV1KDa14|Y z#+XVNSZt)>hQ)NkfEYTgCOntQIJxS&YDyb(Qwgmm)r6+0%`r+QaT5S*oGDbmA@Elf z4)$bvc@{h7)(Iwp6y3yW@SB$U-5_JGL8iu-^;gzr@E5wU^fVATDOwRoxagA#b1kSW z1P%lflNdvTP~dgz{}mma5j34vIwC0AorDZ2(Y^oU>U0!y7@awCxwgE{MgB!DO7DUt z8QuQ?EAbm^DW}wMSb8ANuh^QN19poV!Av5pkC_X*LR~SkT*%%n;HVo=NS^6&bGEU5Hj?- zg!8%k1is{=yZ3fNpy!Pv^#C9^xzTF-Ps{hPhcrC&{m|hK(SXPI-(F{FY0$|B!~Tap zz6f?ecv2ip0Vm7;dx-CWh?Wag6Lh5*7)nhI)3I8(AYO!x9Gab7k~}LS-HdfZJSF$8 z=Wy?)=g~vs9(8V4#)oOq3S=B;9xqEP4M1DCBoSkaqe!!*P$vtB2!|OOqbU~7^^kG) zuq<>|ynJq)1e8){1V}(R+FBdJ2^(%%-3PzAAKNX?;awn6#~IC+^s6?xejfx`7Wb=Pj`CGYff;xVqmxO<1L5z|NFwVOBsb4j5;a(g9a6mLwuXa7EYWqEg?dLYDvQ z0_wq9*U5;(Uv3H0z_2(j-Y|+1)4rvyEQT&O?fYYbjxJ=S81BG=ztNTRvuWvRB7zjI zqQir>mMFO4NXT>XTH%YGb}#hPo?D0b4u5W2O@dNlJ@P z8ji>P6!wXIqT()xC#?dFl$0i)d_Kt!of;LDT>SjFxFe~X5=%{l+*}x{E=n;R2S*AR zw?+%pMKMSOe>*}(X>{*B6` zuA~(^G&a*+5M`bOx%CLG$UFssP||V(DOsY|-14I4%g?Ll*~p#0^sxfXPX&HmCL5~X z%CsRW(rJ_!P^el}eH0OkH8!GzIZ#|g1x86o-bbHVR==%eHj0T{v0{nfYxQ3vH+{`9 z>tpHq6!8lRs5+ISMCJ4)=2g}rdwl-(VZ#*;GNU;-LrEmKlWSI{A47)F9pu6=gt_qI z806xHMQgIO(Z&Ig<)e7zakTMgOi1kDc9?PXZ;LF9Aqy9KW9S^M5!F-5i9=;locZa= zOhvbafvzNarjRoe7KR1FI+haXz1;2?c#KcTM`1jS%z3X)J>2b5*S-&(loB1iN6Ga& zFCBM(PFJdmCvwy@5WaL%P|SDXOjW-)rvb-DI*y|(U?E6}pgbG4*QIYTp%HH1U4 z2*Z$2Qo2Q=_5S1SZF~z|X=<_Gh>mU4=@nidGIHR3fOLO|^0y%pU-iQi>$W?aHLGvf z;mL>zht+!BRYH1m^4ens?u!|B-sWPh=Hlm=AVl_)&{~i4g19mUhq49Lu`KMu;};-T zZs%mA>L9ifk|~W?RFonli}?A6(G(2AA;CirNC(8B)oG>{ zS;d39i=wbd8&WK+@>TZ9g_wJP1TqZ6mDL7h^ z5E!GvqAF@4B+3Q{ZG>T@0kq_@FfSBaCD?lw=H!GfsllhTrf^*-V{=FkS+|IkkT(tl z@OmajRzw%G_`ILR`ayQYfi}Ci++~=r(p^91A%E-3a+h$oFpFoMZboue<_A~Qakau1{u{h7spQ%3gvkljxYH*H42 z0W$(&yGj+^K|0V3;~PyNNxn3UQfLSrCOGoG$=qpj}5&W9C^0UMney=0LH(I7Ud1I zpQOksp_!!95aTKD84+oD$SJ5T&9y~pT&9r{#eOv4Ugg+sajvb;MzHpS!z{X~>lTtl z0MN!T&@wA-=-B5t2=0x0g`qc`-FXkm$>|2~2BojHj9V~^Al^&=Ie1!paVX^oqY{hv zPpqu53N?P48s7u~RU|FpnxgT*N&JuqPSwA-&e$$H_tO?wY4#z73e(SVe&0*cX^e&x z0f1;Em^rP$cMQ)4-ffY>wy5cR@MX z1;UU#fS3Q;8})U_LbteKqp`@XxebY$QS&dPjss0tx~DVOKEd}4b7{GrJ~##neNwrL zM}#rEgO_qhFPY+ev5WBTU2n78>E5Ow#;8>==jEl{+~y?MKmeJ$}mSEg{PO!Y%1DEsHT8 zP`doiFy3K)_Fn$?uc?a&X|?277+EofK=223nE?5{oUvV)Eoo1>XFNxmh)%_-w})6P(h<>B?jsrZt-Tw zw$TZJBqWBArC<5vjnXE!yE;C@f-zs}DP>>;Clf5ec;>k36~|qREHhc0&h~}NYu*2{ zpMqLLB{=+XNodnFVyd_^TuG+%1o|X~#b}8^e&miho_VvpaLTdMsQ|DEu{QP9aP)7FI_sTMdtI z;QGq#;CV;e`gYdJfi>SR5}hHGgU6_DZ)I;CLZ(^!0PP05n<7o3!VbmIABYPPxaV0E zv@rpeNfo3KbfPKqIMCPuWz7Cue*&UX7dQ8;ms35dP^^{Qzlc9k~X$(wR%XXP2}f;w>L@5%&GgB_`{T`p<^6Co3&f*S{!yUn+3|p z1?t!DQ)>_1AAYGDkcm@fYch;)jl4Y{Z#TXFVm}%WKW>6z0us=_C-))I$kR|6%3#K5 zChd4jg%sJeNTABAO@*;(i;iJ=ce9}>85;@$mF8qILI?*IL$1qmy^s1G+RB=rjDAf< z`Ku}+ccm+?9-hj)zPdz2+ibg^mhbp^v1(s4zzK2)W3rdB!*y#!T^@?)t zyc1K{|NKLdT|^NY$ZB!SquB^83Uyb8Ji@J{W9UPRD%VVuZEt5Cnogr<2dN0&x4)AG zg%1vty8vnYL;3(nf?1F7A%M%j8N6mncjrOg`fRG@M_gJVQU~|0F8lk14)3!L-FFy% zUqBb}ol1qzIkJT4X$Ttd=O6VCJ98?n&epMf-=p?UF?K%SphZAsf@`XP3`l(O`p`{@RU z*!%XF*~|6eWWigbI%C(E4@F-seu8*&4BsyOnJ|jlv zjcW}{U0=P5HLjjD%k%68xAsuF^PEAdeAm~T;RRlv(vFUL-eMoNJXaV$-gdrZzWvGh zP;fl{F8J>^87>HfFDMNbGrFNMc(^~*#3tq<`;;e2BBt0FmPXplCN3(%OlpXRb=2)B z1%h2F=5-q%%FMYl*U5;agG-2x{#zksZJ{6SrT06&AF5CU zP&6DX!L!K2f=~03dn+a1l8ed9AEK<)#njY}fa~M$etO;VrXcHMx-GHh2pphG_{1mF z`$+hX?w6OLejyxDblqL*4UAAx1Q-#&Q$=pmkYGVLQP6agHCKP0T#HN9ebdP>>_YTi zbdl(JDr7W@%RC{$TI=og&Rcfn&MmdSHc@->T;EDOn8Da?va~V@xUhI#Sd@1T3v4pI zTBp|Kqwxh}$K;Wqqagq?nT?>pY4r^C$D#M4%Xlv0{=bE3BEQ{QR5N26xYxffJeakY zf~g49IXN1kj*qvKLX10d-i#SKgdD%-J?QW>*$vX~;+r5CjwEad7-G zSg?NvlR%+`LBk+9F`Qk{XWG=h2F1^*y-m+m4WF!kVeNGHyTa!r*mg6#ShVc0`oeJA zw`AN-vGtNT)@bnR((CxxY0%~KVFWDZI?1{h zXz2gB#`+UZxkz&`gWIs=oMj7ADEyNxZqPr3Ros{_3^CD4^l&c`Nrm$dYZxxp6^nRK z>PcfT3dA-Jw&oX$_*mV6X_N6hlBaH3y88ULitiZ$erK${Pt~BHz2j*A?RKSL&{x=+ zfp;G#r}SyA$T#Z%iJ^Nkvm*3xN2bwVq7NOl0?r?qZi@{<>Q=Ib$0d|(EQvxj(byN? z?1a(3d?r6kfv1Tuj++Q+b~KI6zQaG*6_ZL21m+2w8NEH|qx?Q{tNMEPbe8lhN4)RINq;`sK?bXu@s!O-i z-h{r_2yySl(az1K_xK*Q$BSP^dQ3!ug|gaye#-Zz6MMhRoo_>^m&u^=v=SbG)Zk)P z@jf_PE4>W|5kqwG_Y@KZ_Mya&Ufq^dKi9q7ny0>UULAE5!yi-L+wZ#q-#6epCdzPH zs&sBFuDsq{3|`OM{BpGxnE?Ll%bz1pY#4d|4RG>Vo6FKk_XVRPj|P3>Dh{&-m06y# z_z5@mw8R&cbXyh|q~nN+D3jX$-YMKeNj?M~%0bRcvb?5}{L_Wc% z$9_C@h|kC4URA8LbD+p^huoT`ghy3OejhSO4sR@-*eN-E1hL6mlwTK zK^7FC1CGqu+o$WYxxAin5V{u7Ij^ej5&?WMI71%`#S2{`jftG4H=_A2EuQRhuyW}*UsBQ}hKHTwOH?)}tZ?$g<058o+Z3WiNB zSLAX@h9^8pl17NkgiSo`7lQ4ape}C8G`HvT!IcYSw|vh_?Z@miqC3>0?~$C}^Sy_! z^qg)qF8h@j;PF0n`>Cn&>&XRV0ex`+`T6OYL6vIPJ?+u^TeAR11qveGc(!6cok}9v zb;OADNY~DM!Cg6cDoPu`WFw zmQ|GEH=dH{g|sFeIkAAY#*qAMkmu?W;rU7EkZ?g-K&7@CFO@yc_?JIv955lumgF$r zP^f6}eUkxZ+u2NejF!y`4omAqH#odd{xNEZ>cSi%sU?Wss3Tu{c1=Eh%uN_ftn1~p z(-y+T!IPCF2_oUD+?kMjO>x4bZc04}aJ3!Sd%O+&>*(A=y=vIFs(-oPuq7Tpz#}s7 zURrqB;%y2;u@MY3wEhEHN~cX!;K}AXhI5}wuE#GLHB&SO`I=K@=GcXmEATJ(?5z&5-TG;nAAU#l zAKoVW1wMP>N4|#{KQkTf3dzTg%fi#N)@?b!ey<9|A3qMosJI`NweVaQUnExSF=svZY2xSP{;3Z<-TKlhO5=6{*ZrtaMj>O`A}oaVdy)0q3V#prX$-g~PrCdE>>=Qp==CPf|I1!fk>Ou z=<0=hZ||2vJ$cN>icPluk_`=q{8YaRu#Q)xUp<>8yoIS?3ZW^e^fdMtwC`Lt)|6J!?B0ubT4t(Q0GZ@9aMSe?Wl0&l7Wt5B^Y~AkUQ< zUcr$8f*5Jyxa>Nln{|25>+Mw z0Id8X&Z2@h5;Xm9&(1#j3rNHd?}dz9h=Q!75Q^wp+*+&TC9m8mLIkAf0fp6s5qg95 zWA^bIj{C)T?E(;kAWAQO`77W28*jbu;eBSN5y#qXW@bv77!V*5MKctuw0qTTM;)NhFmAMBep9779?pSS0mYQ|^!iIdzyPEQ46US= zipsch##ehOL<0*rByy3NL4{bY&LaRoY&tlpojrY`b?JC>Ya>yxRHS&_Apfaf|MgG4;6?QioLT3g z2RFU;=k|U2Gl#$YRj$|nhc9p<&GY+y=dDOIdD&Cve{k*i`1s*}`uH2Jy6X4tzxT*W zyoCK^Y4v~QtU2~`^@b-ENk#(^hyfZgibyB{jADlP@n3AeouVjk`i0+{#}^na8T1M8OW(M$JoFtyRwW_=L^aN8 zE=jGHG&mdm=1mV$Zy`(BG|$SupSqZmH3%Ar-u$sIzx&lM02BbN{38evjF=fgt86|3 z07a(iV2B8~P{^H2{qM{!eSe|Y-y0xsD@i<~A|N^hKmt=|3W%tviee}Lrf8MO5Y2e# zAx1=WfHss1t7?3rD#UR3;|VsYl@|=P>imQ#br{;UkO6Uh>Q8QEXSR|}2_=BNh=s8z z05VmEP*7wwF$PQ-)x+Tjm&T`(w_W$6ji;U!=kJTXyV12v2MEZBjBG|mM8Kp31mxRt z%RR--KTJ_I9f_o1A_PQ65laH<1po4)6mWwNC7#3G2L zkW17P0zmZWmY0%lbeLnFC&VN`i$#9bsp*qWNgg^B4=$lqfzcFMs@NU^3{`0g>WTPB zEWiE8!w-J!F?3*nXKtgfzPa_3(_!}``BDjKWJU0R zMQLI>vd+~v018-cr2`ZLaHiW32M)a2SA2mLiB69h=)C5+X&wWhwU!M$4`iT_3P%!-E{fr$7Roe;qT5E(E?Rf$#X0YGXJ>}VvX zwUZN@*=XW}!ay(}0s^6$DJGSc8ObLg>X?-b9qipbzi#8?yKcH?ddntUxFdA#V;WOR znZS_;bw;QJNaV-^no-Igdxtq3#mu5E9`>47USU!oODPKHCI6R;-HBUht|R$kbIm!8 zq-q3; zj4Bmh#z0N!H?H>o^vku0=HUK4D2fSC1Tlm-V9vtCmU?X!N=YhaPAfqSs6wCFxZ>6?)Mg6VpNF|%0MvBUW+S5@l{44`VnkFTMM1G@5HXA& zR|CLELu+N#7;&Xm{uj|#_;@gTr5hghXiyPrxB{O{C3Hf|pWJS&uV*Q^j%gvF;E0T{ zVm=$9BUMlbq!vN~si7J`_vm25hSl%A@wTz4wPEgtvh#@Zqv9Nag4GNol2bwh9s)Kh zrV3;6y}L9x-F#w9$B4L4^cn$0*bo91j(++=-M$Vw5zAhw{l?lWnGp5p{DVl+UKB;=tv?naNx+^Exm zQDlSCB7?DkAUGBblE)=&uRCk|6@N+Xt@-RdZfxA88@}_oPu{cV*3W(ZrloH8(BYXM z-?IlfH5D^iH9kH*IR;?t(Q&Oe&`T~_d)&!qQ0qK2HDpAp)muLCOUuh^)~rF3O=n#A zjFUHf=~JIu9$Ix36^JU%s6z4J5fT7U zMx=z#W>+?N0)sKtSW zei%LB`D@O8vqmX;dl9tWnu4*X{LC{i{^&PuFmr%_5U3*3AR5?-JCC25o(?4vt02uB zo_X&(e&HF|N7Tw&4!wDguB1{rPp8e;ynY| zlVU#@=rF%`XpDlD*qPzwL{PD$2*a-|3a%m$;!36X#Cax|IsmB_+aS}aU)@O8_{2F9uwE=R8X^-pFq0~5OR35u zG!r0HF#ttUGz3LKLc}=eOpp1k=UlE}vV4!vR$~axrO3dRngN1CRs%+0G%_j@**k9fG)O1I5;R`gbrBI>W4%NprDv$tsSC8e&`lxt~%jaZ%^mH9UuDh zat5-IdelNmy`vyXL=0stkQ|P$>euRVVcvz9CCLEMWnK*U(HUvh@poV1u0EaK_LcCJ zTUJ8Juu4R8W{M~_?Dkid-v9?=I5;=^jk#I4{nr0OgNC0JJ5PLx2s0z%O1$L%(qPEU zh$?8&%8STE5=fqZp}z6C^|N-^kwbA$2NQ#mF-SD#!D1X6xAqQKALo#>mIX1YWM+!4 z2!iC51!K1mfayzqXLRFFg~1*vdqfU3+%7uj!jFFahXhg4z*sAOngO7-Tch5m zgoq@B(y2LD--_UzhTRAE9KZccEz8e*_Uo^I?aP1VjlaI{v0dwT>~ONIkZ!*8xqtDs zPrdc37o1YB?}>2la=#ai0ECdt4A8VPXI5o{g2HgbLOAqe4c{3u)1$c@&86<#sw}Qc z-FTW>$sG^@2xv;mL@p`-1TwV5Kny`h`QHdD|HXhu2?%s;&7ah6ZfT`s9t(?6RCGwE ztm>c&c!kx1-VlKe4YbP6GGxyxs0z-3NS)KA<^I#2`;yT$)8*_f=qAar0SZt|gp`m_ z2-qBg2c}`dP11<_=EL{yXO5(XViv?SKtGs?%loJy=8Ltbo`&aa4+}G{KEbu^)PFQA z??I#WYa0_gpF)$Tl}B#s&d&P;kl6&BXN`iyh+?1`y?14;VTitr!i>fxvN^KS@X!(+ zw+?>lQdvEk-Mb%_dr~PhJdmLnIB%wC75osbf;|D61B^pj3=NxC!2fOC#7|C~f44~a z?|fSj*-QxypmHx@wSIwN-T@m57@+}LR4@YDvMzn^&+_m6R5Fsa;={6NELdh(h}O^R3!s7 zLVDa1WPq-sM+CJc!9#=CjS&(WCH6Q3;h+&1M{)wpYDOfWtWfR6=@@1SS7=9s)^@lx z%T8+5H`nV4LaveGwuErJaS5qQHBnLjC7z(i?^JKtTtN){i@P>yAkMZ!5&UInFl*J{U z>&JsjHs6PCH`rWy>Sll0$zk@88#~KoW98hclqDy9jbsu9yLYJpXv!bui2>5<|k>(tUJBc-a;x+6hHz(j1WkxxF!L1 z3LVSC*qX~m&UdiOuH7-@WJEdG-7@J%&ZwuxZ2QO`EHN z&U??m0Pf1GFIm5KhlRrv(`%mpyqEmk>wZcD-g3*0U;XMgKk|>Co*d84JNFWbWuP8m z^S(QNc-!^&aux_1n=;y1Puf`PtL74nhbHr?z9XX{DcX=LIWq#%N?gnEJF1YgaXG}p z{c<*FFshNOdjwQP6;%X6txgUw9d55|h*?7h(9B@EmhNc#t&PT1tp*4^i(-aQonWF^ zseKR)s>cGMM*u+pQE!OIMnl_@nu61maLlKj817gc+&0&nH`{ag(ET^x@S^|n8>wHA zU_Wdx8E&8$ktBq2|Lm=YJC1^{lXLIqP5xi>*=H^ zzh*?|mxM$6DW)6!W|!NDxB> z$Tf2wM2y&3l0%Py0E7xaRCTVP zY-or;Lp&Q0np74!`i~ySKdE2-FO-31rVgDVf(OzSj2n=lf>vxAMK+U>2EFm>xw@d zJK;^*D?{f|=W1F(@G)W)ai<|^HInho-~EU8Kho`@Qk9JWh=g>`Ip?Qo258=~^T?Qb zpFI1jOUGADLNSP%Q|PwG);;}-D}VasFYM*LJAd@!uYUd87hQbn*5l43Y$4+Ne&dbB z{A^Zl1=B)>fY+wFz2=*V>qQvIa03p<;C;hO`B=h?!V{NHgezwv0dOvHt_(-Zd|8Bm zYDft)At*#csz9;~SUq#u09qb4*3#{*`uZ$Oki~SMA)v7#seyta0Fy%^QvfvrL#hfT z262kO9MLHlftZ;&*FqX)*C~o0bp|&t_74?SY89ac_wL#|bN>U+e95o6bVdd_0yAbv zWScuMVA=hUBikvn_ZomSF0o6>XE;)UC4SMEq(aB}j3 z3zJi)19Y*riW)m~@lNa?R%)3;GBIRA)liyrTHBr!>ZknmKY#7SHG16YWWHCGB^sDK z002uQU_k@okU9fEM!{6osYCKU6(|obmDA1ol~0xzJq0IP`rv-w?Mqd>n0aJF^?*^$ zt5Zf&B_cEf17iX+Ci)Ktz&|;3{`X4z{=)%$H9Iv0^$4n{)fUFkP!)hywe^ixCx7`G z_u`8ajB)qj`XEOzBUCH3SW>Jdt4~hXomXqE^V-!gfD9xzaOfbaQbNI)z;+A-#Jz8v z-n-r&n$*^kJ7pTi+S*-&QkiN3k;w@GM@HybeaAi5{ouy?c3EXHVlaghj^BCOiKm3T z@Z@}&kn=(E@v+gXufDWaParReqm>k_L!mRiddIV${jBFb_Zc&X_Kc6V&OY}^0Qjdr z^P(HSanrB}10UB9ALjtb|fDTDb z4ABvhLS?J1P(O@FAQfyQ_3Y6)LGSP84-ZOVf*1*_2{oG`U<89V{oHH*f_tS<}V{8%OE7**r|II{UmgbavhRuGir6&P$ehws+PN5+MMKC<(BN zDMAIQP((zEm^foXiU5^<5j^VnDyUDv!oK>4zZ3udtNllIt60SZH-OYY97s@yPEC{v z1Q5Yf1snOvLhAqgxpVBD{8zsO7~84Qf9bR>@KaB6FTBWaUTcHdxPO^d ziDMZli35wv!8fUWTspbK)mM30hO%c4Fi0%a97W0@66rv6O>j*L-%jIurozK@)?8pe zax1;!O#f?FG@f=2LlO2Kb;czt0FfAix=kdGpdT>(Xo-|J@0vCEUNSv zM#s#vM;EqjU-#}meIs&H2T`dDP&ddc_5&M2w$4DRAfosG`p^E|dp^2tbsGp!Q^h<2 zfF&NvoScZ%k?L$>cqGEZ-C}QlKovI|0Tc<{zchOfJrM?o=+t5*KD3pH^lGU>V8k%# zv+;yl%tVeirRla-b8{oDp_L}N7$|rnBSSPoJ4W1Rt2!}bK-3|wqmnKol8`Zjg0NxT zQN}nI<<8~)4a@!65Y3FL<^9m}3RPsO8Q=V)JF;%~qG!GuU~hdksMT$LiV}>E~(XZcl!7v@>9{%UA-1dnd$^!?jsm0o+3P$5p$RU{tdUQ@zSwYpAfuf2dR_77w z@uG{p9 z%?;UVqN*@SAJ+G5ep-LOQM_v!=8&yGNF&x0CE4}x;2(Zq z_wP$j+2poumAsFII-O060sP>UN6rFF@V41 z(zDMx!IK=5!(G)P`>Kl-mks5bnIa`FK z5P}(AJUt>oRRF5&HC8lLsMyj5ghZ7}Z#WD^V*mkE2CITR!3a9aNpnE>*?zx+P-H2(i2 z!2jg+-=mydNp?fzDzZjYRkhOQJ77`O)opswh5m(4au=TfNc7m@5CV^jlQ1>gXoTJZH6xUHXl@7v$@E5E&QvYBN` zP%|M!jFgjD1jqmfz|L4zmCXoMh|$1BZr)5N$zmuKk)9wEpJju`J31N0FqyX8Yc~(~o}t zgHL(Q&&}^WT$*$`om!ICYH6+6s5jfdi4v0rD+hT#@JMQ;s0p%KQ0F)|t2K;x9g*>(Hslf199pU0~-VoPYw%FMzbmxjhz{qnUX~`5=_~pMBNY$4vNPHgXOs5 z$U%mRJv>Z014IUse-T|oSediL9#5j;)iv+UIdG;191)C&4V)2}sY=y7R-wXV3|_$- z5l}=EFlU+}rH&5f7~FpMuB@J1cjG-TyZT9g|4+a7gKvKA=I?&K z+1{|}Nv|K>bfOf!-r^&=K;TPct~T2aoB}8dGI&%m?GGUD#84nPpS1}y12ALqjG<@c zVraMQq$i~>dw%-zr@7S|vc)AiJP(Xw9vrx=R zs#cGVYNLq=RmX~mHdL4Y%cIKv({1F3Ian2f35KaD$HJv>DDGI<#3EENSSw~7UCGg^ zGO2Y%#zNIEtBVVPs}Rs(CM_@krpzu&YFXkF^a<9zYiGD-)Ln1_{`@nuw?5yUcfLU( z2anJ~56A)ml#vGuU5>84rm^n4sp+%E+Q(;JrRXsPLqkGuCK01EXMkjdl(R}i?JHsO zzoy&Ylz-p{-S_+fz&a16;JETqnix0&MRdZsW46|WB}#4?6g}b(#X1# zZ~N{KwryV3+OQ!TX-rO!wZ>ZYW-W0jm+s3D+re5&O^FH*k@7{C&qXY~n zzw!&uf7f5UA9Q}K2is+-xu{BoIxq9|gFW(Fo&v8wIy zxZ7c$We%x&uxMqxUAeXXd*%H9IbI4YDRsxn5j3r|_5gHDpIZ;|02j(9RL_b zw14rRt-{I(MGcU=syfEhC*$LOtkuXoHN3TJVbfG`>K5Fw5jHebENXCuF^L+CL$|OZ zLOmPXG}hiW*4jKG6sT8}d0|wbF>7gN3@kw)aZdZvn<izqn*M@s9@&2Rcu z=`R9IA_f8Hp@@cv37ZHrK?OqGaC85DsqVlV_#1^`1g1XTr$Xrz^A62KuPj)Tbl5D)Zw3#F_Wq*iu; z!}w1 z;ocr#9F)70yPhM+DP)GRkbx)x|9oKSq%o?|Hn_Cb@@})?7Y;9-3SRF zqj_}##Aa&g`tbG7WP2&`1cRb%vLH(1i0b02g3ZGr(Ah%J)3TByDD3AoMY(D z?6!{7N34L9z=4&hgb)pxkc9%X&wC-CwYUuZ0uqOfX6l+i-XUN#)SPf$SYi73>?u#L zz4Y?dmMyK;s@iC4tW~dvqUd%9d5F=}OsmW`GX``>0A`F-nOA_~@NvE(Lout8Iq+Z2 zhK}`R|7t${|MO$W%n%8H5qX#lSzTyI2Ck}$4JxuVB6$D>R2(9>SK>NR6%;_7RmZbd z>suvEA(0Bq4P+V_ky*z_amVW9v~Ag0JIBvCZT$R`{aIUZ^*A*hs03wpW>!j3h?Z8H z9344n-P&`uj-Ih99dE^MLHR(U7^)Kj>O*W)x)3*pG!-p+Z9bP9|Fuk?k??qkhmy(B z!5@EV@V##ntgcK1l`c7hM8OmVEk|Y>YeSZrM6am8Cbi<8yZxD)YG>>$7G{#M)Al{I zH_Sh}<*W;>-vvXZ5=7W1Dyl$)po(C~AgnPWD@QgkSxP3K^6>RHUVPQn(Tq?5p%d|e zZc&(xCw`Pc)YP0J2UABBObA(!6~GZGVgy42gDS&Qg;bFuXlW8Gu1fs0Pn+JC8VfN5 z@IdmohpVbNjzwP56CIv-R&&H0AStMrnRAX2Ia=v7K{f#~b;J$~z%0QLb%nuP)V=-Q zOdg(afDvL923qw|0H~-ojLV@aU0ADoKoz#OlG8`BHB23&4g$wm_nyG!4$gvy_uO#n z)>F^U=YQn6N!1?FQfQ8;$ii{w%VQ6=KXXlX)r;f4du?`^&psa!1(gj#1P62Z-2I%4 z5qdW=zJK?wjoY96M01Bxm8Ag)tkuPhY5)#>R6#Vh+8sB(?UXZ5Esqp5Izk}***(j9 z?woX6Hj041}v(AVOE&asXi9%!J6PDiNs}44q%L z(s@zdpz9!-!6>*@4qTi|Gy~B2!IqK+K{V&zk}#}gdq(Wxsl*WTm8u!!_Lj=meuLxxKDg5ZLH#?4WXYvE}`!VR3Y{BVBb#}DMa%b)#c-@stq zxvwRSExtAhVQ_HzrA2pdW}^|z0ao8qAV4)nLJP4ql1{G=-40nEi_$4tCx@tBvW9gCK5dP5=#e(v#8)AngJ$?B?h&;Hucm4 zcmL>=GtOL4AS5s~bAVEIGVoPlx)9RmPJZ*28h?Nq+`y=(DtXDcJ34HLMaA_pO| zfwf06$F7WnEmNy6y5h;b-Vqq|2aAW=TVK&1x$K><{iE)D)*98dt74v3mE(CzltW-+1zc z?bA+atzF|B=#j<36xFoClT?=rBdH0IsVbodBTyp%8iLPY#h>?hPWOMd;qyvKhA_mc z40UB>j6jB@!(y31(HS#}Dj^V|8Ac)|L<4aq2Cl*{p!upGH*^L8AvtjeJ?~=ox@V`q z_ELP^vzwQkpY2>rqp5nZ#0DG|6U$SVIN!)>O;?|+ubOIa+}zl)b8PGSY*l6v%U%bg z1Pu(SfdUsLGFs%iPq(DjDDS&P|NPJAUj1uxfBRM2u+)9pYkvhjBB3uiHa3(W|J?E? z|Goxm5vq-g8(8oN29|(EC}7p9WXm=Q5i|%mZ!8jwf%96if3A7i$#lYm)0}JDAHMmf zQ_k6-(Ns`lSp}*KL;@6xf+QHpTx1g~y!70v^OpA?IqmdwXUY;V8O~mSR_Nv&6b={V z-aPln6A34bWdz_NG7u!BC{O|rn-@l7m8xAC#%F>Nn3_k5MgvhXX?t6nr7iCPxfhT? z5e8sWq(%di0@7PCfM%Z~lGn zxtKqKl%QI~f~7`--EaJ@-#)ys@a{kTYeT0{5=fPsqvEi#+yJ7(iLr4aSCpMz4+cTh zd=i}kG@Jv}8$SN0dmhaP`MR6#DRv$wJ9m^@w-u{b$D+jEqUMM~C0Ob#m!cIS89 z-M{7b`J3;Uz3;x|q6D)TjR-)bLIf1#&~z9E3!=!wPiBbCU{WyrPj>2{5kRaAl?Ft> zW`dxVzQYXJs(sII&KS}eY~Bwvwg-6IDRA5 znrx!^0xm6T5u=KsXsRW%$E1NN_%ynVeRG6H$I|9lQcE}$wI%46LCb_p)tqw{ax`LY z_z8n1hJ(dtKe+f0pIH9dcZ%VE2jxQ#9{GhI-?ZtBi?!%r(s0(9|MKmIQGg>DSrC8} zIap-K12XT}i5u5Rr>CsWr-(6{I`a~dvN{xtao3UT;!QR;w|d<G(1EN%B)MywYBE|sH=c$YOi{&|Ioqed^10b?s;0zSds^PtwRN&pkh&L<^*5rOm z<~B6zs?^V;Pzg+?9uOnu1bmF2zkZ8UY0DX*{jgS~R5DC5vG zIyADu6E?7T%4oBS21YUl1Rw%5Acx`rYRp0LP+9C74EoW?Scevj$3tmW z4Q|8X!+U@4ci;SXAH3#qxg={fF>6mWCdXErP@Z>}dP|+9?l-P^%M~xWx;%IY@~&Hb z64g)rZ&#kW_~Uy=*GvowT9{`5n3|Gp$M?@Uk+yG*V|6$*4-37*Bx6Jq0T!SHqXJPh zL2(L{BsEu0YPE)+J}FzXHESPs>49jX!sVbuV*>|9StEm~He;Qgnev{8x_8~PaOd6g zcl~(wp8FRceRRge1EE0x9R@lNBNU&oCN|XSQ}|D%a<0CI;kSWID}}d$kO3GCy_PCS zRdfnfm`khLMk4@0Fd$yP7Ej*-XCI%Qw8NjY0k*7h$%r#3pl9>*WmzUxuxgAtD0+no zGi9~O)jYn+)ka;~v|59chEM9`YMf@|*et5eL!6=51I+`5lp>BO*1gE!$Zg9X`P9<8 zK5<~-AR)w+{1zfG1^b=f|KmUS-8T(7_i>uyU@*7&XUfGH#wI}sh71LPD%Smmjkt3Q z1ki35GPGWZc~Q$jaw)aPWspIDe6Ic3U#wqsdVk*|?JYn1`S<_zaoeX)y6lvNgZDRF zD*{;pSSqL?B}UOlryyVp$@IAqR-dx@_y_mz1yCZbLh;N2#A7@lWx!ZjD~te`Axx!k zLUUrOPDNSvz$qGvGCLJ8h;b!gYKZt4Zmdk8`k)M%hVw&HWQQV!$dS^H49Y^IJ>F9f zKYcf>SPm~9~mR@+8 z`{lo;E1vGmD?~Iwt*@QlXJ&DQpEV9AzyY~lgL5k?SCs6+|ZFsUiJ zJk*OLhx&()M96DdCz<4Q%~&$gc3Faug_2ajX3V&&4qaB;a@^W2C+>L8ix`o#+ugOR zd(V9fKfd?iJ@*}bVAs;FhYuBn0zzeKSFI$WIxKncKgTHN@vW60I7S9gz^KD#SK<(Z z>dMkdsy~Xx6)(y_8x7pBnvdULCvW%1ZK|KTS+=h8tqE2K9HT8kr)#qdT@o@B$ek36 z8Z4G*Dc8q0B%@oBwHwpXNpOxZ0{~2jfRVf~lU5}=nkB$luzot4)@w)XA@e%RlCl$MFS#einu5u=$_;@8`MbT??IK^i^Eg9~AC(SZu)(L5z}9$$m&C*6iA zY){3RCBL;nN3pzT2B#YyxwI}=bg_oSFh3jDu1?QcXS0XdGK^5m{G2olw%2H1EEb)c zgi=@}VhY*;NsA;{XQ8$Ew=Txfk!92n+s~{5!FC2f~}l5fEdlHv50{I1OYf$ z`a=tIn|jId?Z&9rB4Ca_N>mDD?(xFH)Q;`Q!2tw-%CpFbUO^2-Log&F+EB;ojOPnE zJSe-O%uYmxX3^8f+N#wt1&o#udZr+HATQ_pc~7fQD}u*Y9y+`ZtkMD*f+-jxlbOIu zh!?3>+uUfMSmzO+^|a_(NQ@ZG9GR#=bl`!UA&^Q1qbE}XW->ONsMo!t_uqH$+;h(S z?v1w_1v4M9ARUAwalA1b2kEp9Cv1OW)|~a*6kI&9)!GhbQwN;=iH&L0vRZ8n~qOAGrjzH-nlWf z8!pcw7HFIz3i-OD7C5JvRuTkMFEWU|Iqh}PYq~0{Pmg7jlgZ>nV{8JOO@s{8w6JI( zQHfJ>-nHt8HM0gl9Z^+_1CK2}wx|E_BZqeFI{eVCnLWFYKDPJJ++5F~Dhi%3+Z$dz zmD0xn=y2e=BH9GdAq430#WtOvx510f_a1#n0-*48cSVB<6&w}G~9_B+Ougo8Y z!*TH)Uw8e1f*~R`>z3BQvGjVf)R8-PkG<2kkQ02Av2`_z|}{L1`0wI!lt@~4FJfaZfRya>-ChWs}@2u zCNn!`60G!tQW4e-Dpp_hi7QwM>NO2$kpNW^Lr1kr^OttTlGl{A5N0;~)_LNCj6`*5o`z zjb1^;0UMBFOnoAv0MO*5=Hy6}8xEI;L*EQua`^?KT?C%GdyghA$>UOU!v#zEwrgI$@tIGVBg_%N zC8m&yc`nNNURWw!zek7Xirq)EN9Nb;J+OOx#P3|q7j4FMQ!cBSAT!m#H^|pbo%5*G z0su^e;ZUgP$W)}Q+6r1 zQNub~3x;~oa&d8a-=4Ys`xf^dIJ$e!+@Zq<4jr7CIl6f0@Z9{|a)<${$j23J#p9iF zwFxkI!ZGy3wrEAaX!3-kr#g@R{UZs7CY&dR0#z|gsdq0eF@G)85PoTY^`(c&31Z)5lLexSc$5I|Uxc}DM_S}8v9(P}PWZy!o&Z{>i zQ)?1elQbjpu3gt8B|vU4iX#g}Kl)yGsVv>qfAB!NHBl^Fm$cXQKYMrg&e?2jOS%JH z?no%yat;z@u~RPgrvCN~e%nd$f%_KU`qA>{`$B)g^$qesTc<~V=QY_+Uq#hAu6m!5 zU%k<7-*n<{U3)8mE9P$q%a6F)Dh^tBc7w%q!%5&ye9N=0y7uee-L`IQpdn%3WIdYG zO^b^M^Dx9ynCUPTua%BLng-?rdh8lhiXWMyY1>m1azdq|)voLQn+) zH|%fBkOU(R) z%o{|xX)eEGX|MvM!B2kc*3lO~^L?NA3f0#$f`a_;@85Uz&%R*^8BA*cpZwF`kBByR zFQCJsgd~EZVWI}aDx{(4YiS_5Ty(844P^jzjwH>F&XhY&J^r}Ub^=7xVDk%kCwT8m zRMG6M%+x@=gDnlNjTN>PMo+lhW`5kCt<863-@L?L zO(2RTgw9;Tz6l9=^Cnh_s8EBJeX+cfx+TrTm`oJP*x7%y^XLpBrY-cNQ|X$CbaXl! zU6YQj<;jgnb3(Ch;8ek)Vn3?RBQ6lvg%k2=du;0D(aoox-Uh1!)>M~?I%dnuOSAKH zbF)WgW@ct)=6ka<^K7A8=@+G{K3*l6=`dh%#bFFX ze5J1N_lCnhV)dR|EpF7QRmYKrwwpN8hKVsZ(srvxVZ2RK6E-;pt43*J)Yn>wb&?u7 zb`VM^BlHdWD19gwOeCrT8itUoMJS`?A_8C}t!6rYR@zvbG&bwV7Ot;P+G`+bI)%WC zP%LPFMg-F?)1oarfQz)1DfY4GVYLBz=EhfP%dvMKXk15_=S8 zx~*S&X0mM)6UP z?MuDVSU@UbpAn#{RUe#r13(LaS_Moo#Gr6@C*Mb5TXSSxmWV+SLut_nt86?Sq67ii z1kr;7qe6;^3gC{75slEmL<9gL;aKKJQ@2!*YoN=C_Vl z8Y&W?;1hOLQ00OmrldRTjqT04lFgNYffDAzLYg`b!^1SFFrXt}syKks0<$Lp#Kf^o zI5WpB9n|r)uJ;WW27jp@$vDo+JlcRjkSI5N>I$88MQkY^j1w1%FN(UPG|-Y zl{sY%;*cO|q0)gnKe1-DEzHhy%cjr#`I%ckPYALaTHRW`-8DDz=roP4@~t(Tt@1o#Frvnw!7K+6&{)bG(vn#p0Eor;Ffv+e zx3_HBwjCgXm4MMK00xB8tcTWxn8(oT_4=J|-tFYw?x3^O?f3E!iz1qY5MwZn01-{A zYRxC=*qk@-Vk48WHntm3uTwLNX~Q^GbgT(d0!9kP3QC9=0^|w+um_1#ZCNMjkMTqx2)U*{K^ zFMV?Bg_la%)6!fx5?X2F$rm@CWD&iy%Jd;?>3$~zp>y#=h4>0HmzU$m%s43?|$PuCv2GtF)}$9NgGnaHETB z{=G|m0jRW8mA;XIMT3F+$aio2#P=>;t*{q30s-Qc8=5B+OD8}18A#5G-3gQ>mq{cg zQozJwuE36Cr|&1nFTLdS8}IyBv%a?BeHXz8IDBMwtkr(y%U)~P!15tsK%|r!Ax1*P za>;GJxU;0o5B}qm&!tlR{J!g;(OP%edk=m8tu#6_ec{W?x%%Gk{pH4|{H7M2-mY&Y zDHR<7*qRHU-HjB@HqboCh=2Jj5lm zfk_8q0gx*wLJ5*11at}@NP!r*2JO0UPccBvU=$z#h(W;s1_2-d1Ox#n07`%e5Y2)? zX;2bG1T~2gqAS57VnHwv3I@h#W|p&pMiC`23Zf>FtiV`mh!}@T3v?M$-O>qYw8@WS zZ8c`olucu{hLbgzOo?kFrX(fAG8Vbn0imc-m`g`2>Jd;dP;97ISJMQhphkkF8yx8# zI-qm=i>3X(bHrrPL5FL^enes?_U0J4@T;Xi>%iyIccKCahH<$J{f;2;*rYS|PzpIS zl<3s4DRG8J9=ij8yldvg5$>e!8QVr0X@2u8E%noechh5V!IN4~I!VGZ6n#q?Q3d+B z!7Pv&QRJ50{o~$8|EV@tB=7!xm{?mZFTh}dQBOJJj7+TreBWJr_MUzEKY#0+jm@X~ z(X#;H!@u<_pZ=QnwDazKs0;ZSw;EA1XtsvcM|X_}D$&@emQo2rN*+QwG4A@yTE zEld`*AOl2G00IKjK2^beU~17JgJTs#MFT-pN*X33se7bf-oBVGMx{zns9Iq)%nU37 z6N#w70N_zVP?@OX)f-1n8gKmQ&gIRQJqOWjc2A56c@7kij3J2*Q-e|fQLWd%^osKi z9$Eg>7q86+J%(atzBf71{?oU;amUG*2+Y$|L-RvW%$LQikY^MFNong1*WT=xXKItY zv|z2~Xy>l4YLx9S`=VcE0C}$L^u#|&52X$>n65l4b#sZaBlbo$q@d;uQi2k706IV=m7uu* zs%c*}kSRd~C=E)p5=jjT(b6O$DOv!GthtDQDH(_gnt)Z@S`!Hbm0CKYmMBI>A_2@P zvKo^*#=7xXNIh|;)K(rv-}cEUxH0mR=*P%6k;e>}EJPJW5IKr*)|nFk;KW%*>VuWY zt{RfnT%xYdoT+sYOYJQz9eJd?=aKn+kJ!TA*xAP@^*S|1%UYJY5tk;-+|Z0c@>mLj zFMYd=9rUS{1As!ya&o<`KJkj)EFZY*`<*^eBSEMelt{rz5>(RE77pHT0@j?g!Cos0 z>{9mRt#tM}o$E8Rn_4B#OTQZ|I`v!zAV&;QN;F4SAdgCWLO$^6h5pRwi=UodaD}bk zTHCrAl(wFF_DLgr$C8oaR~|WV#tEnW$(!D=X7$GJeEVxReEORk*4I7NI|86dzyRtU z1S^~p=9D|uPGkn%+VHEg`u)q{{$5_0+f|9knMOn;DFwiYD{2$~D=0z)B>~ve>mTUp zrbfE4QEO+u8wx`URK@&~AXzkDZJ8VZfGGkEneLSvSp|^EDt$6DiwabVb6g>z8UT0$ zc{~=U>ano$4^)4KRwZt8E1gU{1Sl;=Pil}>ClvuAq5zN@Qboy#APDNK1I*L_#xmcP z^7d|cv{O`E9xy^s1U8h4nPx+@Mr23~N;NutJiB~#t6ro1vkQ%8_Rd@8UA-*#f1Yv7 z$iSG`M?hw8W`s3ERq|;)g{1xC+kbS&T@NoV6{{x3uYUT|MpkbTT_j4tQUJy<4}(Pu z^Mm|gmX5*Xc^`Z8>((xRWaF8Qn2SX#Lx6#v@|%m4jF{vE_eGl;-13IQcYZVP^r&8g zr~xqvgropk-*9xK>D3@K4ywnTNfCN&en8X_YiVQQ3!GHOk{nI?n* zd4eF4uaVV&6g3xEki|Vm@A;u0-M+Nv!N-31`Fyr0=DNNaN5^?|JaO$ZVW}nHCYmE@ ztdG@7X?J5S(x`-_%sDUmWtsN|xkaF4yfw99?U@&6Qv)x_zAyjv!}l-E!&+O~Bajx= z)6<|Bz?n30&Ko>B)$mKzYNg2N;NBP&BK;=p4X5CI~Ax@>#A z<=VLmo|>A)a~DhP%M zs?iLTfujY8>;YqyZNf+mbbHI<-fl5hh=CXbSe0!xRMX%wb!lap5)UlZZv#M$aYNm2 z%u+|#5sAR8psI1`%dEWqD3!}-xTsJytFY4sfS|4lQ3nFmDj|g`&?!Qw&bE^GbTs)Lt{3|a@GtlL`tq9r(Wc9##q6sl7 z2$KsKoPiTx4oX)pop#oRr<{Eu82~m6deWcm#QBldj-fro)nsIpZBrf3Hibibdkc?V zbIE1U8${JW=*a5zQ@3-nq(H_EwKE5ge$+FiliOqdNQ}8bl1R0ygXWs^8^=E7_Q43r#0(gYxbz|24iQx)9&!_(raY05!mO+NW*Hwq7(i(Cp8BvIUE* zF3P|Ffx-DyAZ_uqrp>guestY=K07^&dAIzV>9by1Tf656pTE8UMsSH0K@+qHX)T|d zIsC}o+s}HcGZqC8A$OD(AqVA%h{%fMyjXz%P7|{}B8e9dsYWmci$~pg7iUkuy8F$~ zH}@WOmt7GTj*ymM{(@6a|Jb#60s(=FI!3tJ)Ecd`6QkVaQVOX7Xar;gsZy$l&|EnH zPv+SIDf`9HUy~-Q6Mm>)+}RnJI0lu9Mz6;@8yn(qgb1Pz4Nj^?1A~V;`N1-5t7T&@ zsWC1?5y@CdqUtd5goXlP1cPdsMFL`~NUX#RmCa7!ahnznr^7~Q!+es|q*$Myl=Cj32x~9D6(XMN%nvNc8!J3s30{m13~vudS7MRkf%kz1?J8#&?S(Az(9^6P*$ zgN!=)qPWv0R}M z2Kg3IN|+F+fvJhb7$J%%8WaLtW!!kf=#0o%Baj17W5>)!HA`yFH_>O{65<*pDRTpS zhLj>HAR~*Jf|jU)CZvHRu;fk(5M@!20G2xh1u+e52$j_thycV8xk48)kyICgK}0R9 z>{m4b35bFkSYm_{je{8v{XwXN2FU0L9Aav&fn4WwjFM?iYV4W_Wsxrw3->M_xITa2 z3x{v}KzHArE<53YkNw=fA6%P|9lhuNiIbnP;c36P|6A`7>n5WUrU@HBDruq)2abyM zSADd7>R(%PCbUO;j~qs)rXGMygP5Xa=o+pzlC-9MbF4A3JsDY}IPcS@bUg0+>|=Xp z%jk$m)CmR9guoUS`s+8Iy!ONkba2qDH1I~sNT|R7WU7p61`6g#3=k|qRAVzBE)?q) zyPQnWNz?h?{G;7?J3jgRWXoog0=U*Ydhj2<^i|NIrCJRT@jyR6(6i~fpGYYL2*Tu0 zqW~bH2(W^ZBU83$=nTMw+yK=?*VWQ>wX_6T46))I4;=)@e7OKvv4yn~xL26a%KAWu z^J1}#j;QUJ5K06kLSQmO0v$RLhN>_Ci^xob2q0Fu$15$x(8dE5L<&5bsSN=aYT87c zYL2XL#>9MHNW;5~#-NtP>;v0R&V&e^qkU$Oxj%EQf?CkSelR**$vLASA3(E{LsR)rgj=l<1fu z#s)J4H(*I6G1Al!ykRU0_9T*#>x_)9`}pU-aOl9nohRkG*3Qlr(nA8 z#*dtGGUv+-SgJ8tBl=?T-o?hYOW?#)7x#Rk#@yWWGsV99mJYn9xeC;!W>L+2eO-I! z3&Qf;(w_HET=WWs&1C&DxddESmOt;~Oh-MZgktKD!T__HiyaE}iPNthyW}NF?QnM~ znfvhcl#}-epaxL_hZ00E1m6AFE$4vq$vAX(MW3*kAhAVbC*&w9l13&D z$ngNjU zfx+OD2M13bZSQO)ix#^<7?G3$ptk^oDlF*CD~Bjf%rH}5s?H152+nKQH`KDbm%Gd5 z(Bx!@WLnKs&3KqB4h9ym@<}6@2_bYe-o4Zr&yr19t?j5J9fSzz#0&_uYLV0`hJzCU zQbY`d?g`Wz1g$I<3P4&3r~niQ0oK;j4Yj0|SRQ;1CTIkR0thyo;TRx+fSG|GvX4!` zP%BXqAXzg_W(M(rPJSTIff7OjMFjz5MFmp?tF%82jXQaW0jBoJ1_FuP{-cddBC_s3`CB`1iG)FUtBy@|hn@OL0L;A%R{L#=P2UN)BeK(vuNW|77$AXMM!{* z2?`i^2mPc87{M4#*lGcKDW+gzp34{$$EF@&0Nxuy1%E^<4J3)ITr#*A7BQ`p4pcHB zAnc-Lpa>id0MQLmIG9ADDiO^?D?mw!kd)pE3_XxiOTe-WVa_BLGe4HH>qbr<%=C0_ zcO;6z08J2p*|!jCb(YW@6nnn$muLO@%SVs<1j0Q@>*Vg8uU@rblo}`XkKBS(GjyOr zKn9jXOws|^4UvvRTju&tL%5SWcOmq#G!l)GO$&iC_Lj)CTz%`I`ybdoeHN7WXVS~Z zj=TOF-wu6-I-@~k9c^OMoKg0x1-p zNkM}d8H1>EPBjWMq`&vZ@-v^nL8(As12mb~di<%Y-1leI8%0z?6HNh1M7D_EneFcF zxwFUXlg`ft6$UU304!)2$x0Nj#3TX8l@=-ucwYbjR@Lg4Ch0?+?t|Sv7*RFcs2Ern z&FBd>Uldezar2mbJ> z7d`o9KfCkNi%&TFoOIGj+yis-tfe3`Is^js03;$AP{AQ(XAu>Ud<0BFoIgB!5ILQj zng8-bpSkpkOHM!aJTrLsx{sW_2LAd}6Cb(d;HJ^yxOK@yBc65g&I_LU)+674c4OZ+ z+MCxeENS=dFKcICYx_@)oc7|yd#}mH)=r-Bi;=>@t$!JdeYi*mzy7WDFM2u@w~+MP z<0tI7_6xZzd#)=AN>obNFq5<_^Ty;Dnnbh|l9+DK+N=2Jd!XEpoMk|Y{opLY6ogEA z1D|H=f8A|-D!BWCy2a}sTC*dsuRTukdq-=D7}U)JfXG0TZNB;TIP<#De}LUZ{d^&9 zG|O_)mm16YM)LHi^Bf*_kRg>~r2}$?QPCmzXzawwg8gy{=1X%-0^%_h6ks&;ps7M( zNrNRIkwW3H4n(A>ftn&(hDZQG0afQI?LtIPim{aMKHWmb=S`o2|8EfRdXv z00N_snh^p!gHTaa1WG_*Oal>PBw=!3WfTuC?5m%2hW_%e(dk=A`wTX3o%q^cpoG|~VeMc}Bx5LB@!NFFU>)(iu9i+DnX2X>hM1@_qnHvA3ZjV)t-_2TM1T>%yg6W0 zHV~r(L)#}aL2jE{?rP;lhiX=BMwQfPh4M8-e=&jqspET*vY?vs1_0m8YbydQxi;mNE>K$k^s9Bx%yflR)U;ZGXlK^FmUFyt(!g*VQ^#U~bSZ;sUG8)LUy`Ix3HM3f3k?O637PP~O%uPpjM?{so` z=DfrmXso^|3}#*HeFm4v;%f||z=#8{;?0y27s@{K1|BTBku`;h>-WSr5P{7_2nGd` zGL|X=WXy%+HNXh1kQ7=LeIh_BRf1}1Sdxfpj%pZp137DK>CK!Fk9>H1^&(&bP=^Q# z!s;ME&-z>p%7Hd6ye(;*5z8BmK6CJgkF})}vA1yWM@f_tuqcrgvBXjms@aa0zcXpP zhV&@V)Y6{6n=Ix^1XL|x#*XOZHQhi_Ii{D z$E6%Pviq{%`0S<&uPzRK3!_>s8!m*z8K#8D3hIc>Dd`a5i;RhbQ1jRaPDCA&paZIH z2T(Ic6ae>zXJ7IcU%3`4KavfJ4zVIe>Wa025DiWpX`a#cp_Cp(LAK~TkXSSa0_GwL zff7d*LI%?+^d*?K)iAB?>J0AdELVO6QwA1P#i0k6Dl54mkeM9YaS>H4cOps%H`UTf z?@EZh%HFA1@x6tHzB~pXKm`OeLPG^%v^vs;W^GGWt0&O0JOVi-00hSbjL3pwY(RuY zRQYoept5_id9Bn(I>Jaq_bvDDTI>&0j{!|rT&e~XamYg?L?fu6oKy$BVrq0tGo3HR z0EHuwV+B$I)1kMt`bSM&R$IGfWW#9Vn?Jn!onQaPM?Ub6dv`xJA=#R3$N8}xzB$U; zfqVeyl)ML0RzLz{PfT2&KRom9zj*)D)YQcnoO#Z<=Qmm-0K9n5?SK2HfBcSHtdxq9 zu4w-FQ+7Ul&s}@>AM6A?aM+$XJ-&FzKXNeJf4FvNe>Qix+dkoSu}mJj{?C1!r&`23 zccVM9)|RDvuCbs?dkz)--J{!|5xaXuawAjINSuNTlyjDbZc%jiHMT!Z?NpsVRL{RL z=o}dgW|62Re;r$I zbjdH4au531-Xo*B@QwQB4+35s7yhftVRNetJ#q_NM#-8;BkY*{OmA^=anG*ShNnpL zLU3CwJzZiz9j|+H3vFbTkt<|-QFu?Ku zO4DyON518b-hH$dHQRiS4i18OZxj(DsD)HR$Ja*PrneH+z?_BK$vxTi_QJx=-F#V` znUXVzGBEP7(<$c5^=H2x8$H8u8%S0!`aQV+yEoUz5)EF2)gY-yml$ZLK2mF~dD39d zmvQ%p+jc9iIuRu=x{s2yv4j!>7U>{_T}Q*i2mKwpicehgv7&kMQgZJ5zq$O558c1# zvAJiSv|;bQoGptEq);?P8U%ze)1BOY+^SP9je~s(1%slpVFj~^fM&>K7}-dYKmuq& z0;OdzuzHQ^6O>JAIz@gGAk6IB`_S#z-TdXReevzT`K2%3aKyMGxdIx3ugq|$RkK?u zUeFAWl*Lk^tLwhWNr)B6KR|+F0HW3XdJMRSphhGHtX3-L7T2aUp81}_Aev#Uq%$iG z7E)#HM9?8Bzf$%M^YN-()ofWVsd&N>pPE*tVKHVl&?=3E!2r2hSXFVi)3t14qdt;m zxrQjl<_$@}7>PvAOe7<<_!!i5UH>FWFiUxNd!Q^nzNR}>*xB{b_%p) zxhQVA<3}I*#HYV-&DUmj&yHtqV#|rHy~8zX4wkGe6pT2d>g`A;4jtJ0SMU4a;zIuq z|L`qSQ(L3uO8o7=fBTz0aZ4Ggl0FdAn(2w%k37;HETj2GJ$~-h>({O3qYH&}>I(}x z-}5`3{7amU-}aS1m*P-kgtBDdCbwp(@9(~r8t5IML!Dceu-7N6i~NuSLZk#SV(BSE z3{*&p+cn=Z|D#{#-fhr6cksw}fdqVmIiLk5Z~p%w?7!nRJRYUDx^Jd6(>*y-$w*ku;%skNy@IIroOtZ5j@;a#3L8p#4EgVhEzM3)@+*MK?E%US=6_U?D}an8Pkab`e)5XBs#SS6CH zRLNRj*g5BsUp;>E50dgDrAmk;Y0j!a2{qNGib}V>{a2?~E`;(N#CaJ1X|r*467MF6 z+ZP_o(o{@A!6%4h-Gn>qccJanSHGO+k=-~cp0v>e5Q|uD37{YY(%we@*FVy{>qFHC zKfCkDv*AMzK62{z7r*kGUbnM*^TVI}+FGan?w7A@lrdDX#@dvt$X;w-%zbZk+pFJ+ zF2dez(!(-0B*rF09Z|v^(^ap7gSWu(43)x01+diX<&8H zGcORC?JZ1Ii5!7>=C&g^Onswvp{SmnlmH2!yx`kwUp}_MX`_AAi?mrF26$j8Khx

JN3u^S5&He6=-FolQ`q_;t?+$M`6+q{H z(nzPXp5J zp{&0v^>?cciH2qq!a-C18kB!1?&YM$CaPdAF%S={JostA0C5_^FO9Dr$u~dg@B4nG z0|*HLiWWe%X~R%koTmNnH)NEXb@L0=rQ2ZV3xhk4H&9`0=NhGH4KM|np%JhBBgh_L z*#dfI^V#Rp3;$|xTcJX#YSd6j8dYr?PzyzkD<_gW|9YDK=yPoqLZCsc2Jhdo6^0JC`_pa+#t~~wx=8c`WG3&hH+yBm?qbL61 z&;4JQzV`4>zis6&-m`RlQUbUD4T#3jOlP};1E;?G-#iOAojmv7vSd{l!5paxMaPtM zm!W&ea0JjX2(WqM{JF~;SDw1`#b+;Gcyi;qSt8=-yy13>Lbq=gsnL)r*Xff?bBzPo#visDoptD;5aMgQ9jk*SqAphN?&sAN#1 zD3}Lcf@H^qi<9d5ysE(=8iFVQ05hOi+;92*f1wBr@dZ>aA?Qk;uH`->2$7?zQ9wjC zl!3>CX+BEwMq*GQLaz`J&5RI%0MXdmy+5~O7q&%6u}wQihz_yuQX;-yRL_;wUTA~P zrhrIf5JB5mGlA}NGg_FF2_ha$-2KD;s>7MY(wdAMm;*9p^}>eQ);EHMgmME&Sl1HV ziS|FP?(Q{=3(J=x6N)J~gkbwrdPDfuWqA7=-gxL$uYd7t-+cQ6_Y34~GsE($k9_Il zAOGV2{&#;S#2pI4`Jv}O^NAC$e-o-RkapUYlP#^{kN)7dCrd9{IrsD5^E$p#4%4hF z^J__#tbfxl1&t_tD@GXcI)@+ z&USXo{c-czdT#?$-|JRMUpej_yytDhyMHKIyF=Wa*FW=POXEM`Y&M^SQj=I~RZ3ZF zStXð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

U?+ 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 literal 0 HcmV?d00001 diff --git a/src/qt/res/images/splash_testnet.png b/src/qt/res/images/splash_testnet.png new file mode 100644 index 0000000000000000000000000000000000000000..ac793b473b9ab17316700f852a811172ff42fb85 GIT binary patch literal 149951 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%0D{C;-tQye~1+_ilv-sr`2m|g7%iylzCvF^Y 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

    #kl_`m;B+NWkPpv!>c%CDb4h5!3Z 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 literal 0 HcmV?d00001 diff --git a/src/qt/res/images/wallet.png b/src/qt/res/images/wallet.png index da9d268a6e3afa1ed08842072d59dff35db28cb1..de50b0993e1279e76691e29a9ecbd0f43e300788 100644 GIT binary patch delta 32877 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 MuJx>3>D~MP0hpB)+5i9m delta 33179 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 diff --git a/src/qt/res/src/bitcoin.svg b/src/qt/res/src/bitcoin.svg index 96f1017..b8c7e19 100644 --- a/src/qt/res/src/bitcoin.svg +++ b/src/qt/res/src/bitcoin.svg @@ -1,115 +1,58 @@ - - + - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 8493ac8..f4789c3 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -6,22 +6,20 @@ #include "guiutil.h" #include -#include #include -#include #include +#if QT_VERSION < 0x050000 #include +#endif #include -#include #include +// TODO: add a scrollback limit, as there is currently none // TODO: make it possible to filter out categories (esp debug messages when implemented) // TODO: receive errors and debug messages through ClientModel -const int CONSOLE_SCROLLBACK = 50; const int CONSOLE_HISTORY = 50; - const QSize ICON_SIZE(24, 24); const struct { @@ -37,51 +35,121 @@ const struct { /* Object for executing console RPC commands in a separate thread. */ -class RPCExecutor: public QObject +class RPCExecutor : public QObject { Q_OBJECT + public slots: - void start(); void request(const QString &command); + signals: void reply(int category, const QString &command); }; #include "rpcconsole.moc" -void RPCExecutor::start() +/** + * Split shell command line into a list of arguments. Aims to emulate \c bash and friends. + * + * - Arguments are delimited with whitespace + * - 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 + * - Outside quotes, any character can be escaped + * - 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[in] strCommand Command line to split + */ +bool parseCommandLine(std::vector &args, const std::string &strCommand) { - // Nothing to do + enum CmdParseState + { + STATE_EATING_SPACES, + STATE_ARGUMENT, + STATE_SINGLEQUOTED, + STATE_DOUBLEQUOTED, + STATE_ESCAPE_OUTER, + STATE_ESCAPE_DOUBLEQUOTED + } state = STATE_EATING_SPACES; + std::string curarg; + foreach(char ch, strCommand) + { + switch(state) + { + case STATE_ARGUMENT: // In or after argument + case STATE_EATING_SPACES: // Handle runs of whitespace + switch(ch) + { + 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 + { + args.push_back(curarg); + curarg.clear(); + } + state = STATE_EATING_SPACES; + break; + default: curarg += ch; state = STATE_ARGUMENT; + } + break; + case STATE_SINGLEQUOTED: // Single-quoted string + switch(ch) + { + case '\'': state = STATE_ARGUMENT; break; + default: curarg += ch; + } + 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; + } + } + 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; + } } void RPCExecutor::request(const QString &command) { - // Parse shell-like command line into separate arguments - std::string strMethod; - std::vector strParams; - try { - boost::escaped_list_separator els('\\',' ','\"'); - std::string strCommand = command.toStdString(); - boost::tokenizer > tok(strCommand, els); - - int n = 0; - for(boost::tokenizer >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n) - { - if(n == 0) // First parameter is the command - strMethod = *beg; - else - strParams.push_back(*beg); - } - } - catch(boost::escaped_list_error &e) + std::vector args; + if(!parseCommandLine(args, command.toStdString())) { - emit reply(RPCConsole::CMD_ERROR, QString("Parse error")); + emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; } - - try { + if(args.empty()) + return; // Nothing to do + try + { std::string strPrint; - json_spirit::Value result = tableRPC.execute(strMethod, RPCConvertValues(strMethod, strParams)); + // Convert argument list to JSON objects in method-dependent way, + // and pass it along with the method name to the dispatcher. + json_spirit::Value result = tableRPC.execute( + args[0], + RPCConvertValues(args[0], std::vector(args.begin() + 1, args.end()))); // Format result reply if (result.type() == json_spirit::null_type) @@ -95,7 +163,16 @@ void RPCExecutor::request(const QString &command) } catch (json_spirit::Object& objError) { - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); + try // Nice formatting for standard-format error + { + int code = find_value(objError, "code").get_int(); + std::string message = find_value(objError, "message").get_str(); + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); + } + catch(std::runtime_error &) // raised when converting to invalid type, i.e. missing code or message + { // Show raw JSON object + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); + } } catch (std::exception& e) { @@ -106,17 +183,19 @@ void RPCExecutor::request(const QString &command) RPCConsole::RPCConsole(QWidget *parent) : QDialog(parent), ui(new Ui::RPCConsole), + clientModel(0), historyPtr(0) { ui->setupUi(this); -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export")); ui->showCLOptionsButton->setIcon(QIcon(":/icons/options")); #endif // Install event filter for up and down arrow ui->lineEdit->installEventFilter(this); + ui->messagesWidget->installEventFilter(this); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); @@ -136,15 +215,34 @@ RPCConsole::~RPCConsole() bool RPCConsole::eventFilter(QObject* obj, QEvent *event) { - if(obj == ui->lineEdit) + if(event->type() == QEvent::KeyPress) // Special key handling { - if(event->type() == QEvent::KeyPress) + QKeyEvent *keyevt = static_cast(event); + int key = keyevt->key(); + Qt::KeyboardModifiers mod = keyevt->modifiers(); + switch(key) { - QKeyEvent *key = static_cast(event); - switch(key->key()) + case Qt::Key_Up: if(obj == ui->lineEdit) { browseHistory(-1); return true; } break; + case Qt::Key_Down: if(obj == ui->lineEdit) { browseHistory(1); return true; } break; + case Qt::Key_PageUp: /* pass paging keys to messages widget */ + case Qt::Key_PageDown: + if(obj == ui->lineEdit) { - case Qt::Key_Up: browseHistory(-1); return true; - case Qt::Key_Down: browseHistory(1); return true; + QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt)); + return true; + } + break; + default: + // Typing in messages widget brings focus to line edit, and redirects key there + // Exclude most combinations and keys that emit no text, except paste shortcuts + if(obj == ui->messagesWidget && ( + (!mod && !keyevt->text().isEmpty() && key != Qt::Key_Tab) || + ((mod & Qt::ControlModifier) && key == Qt::Key_V) || + ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert))) + { + ui->lineEdit->setFocus(); + QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt)); + return true; } } } @@ -167,8 +265,6 @@ void RPCConsole::setClientModel(ClientModel *model) setNumConnections(model->getNumConnections()); ui->isTestNet->setChecked(model->isTestNet()); - - setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers()); } } @@ -186,6 +282,8 @@ static QString categoryClass(int category) void RPCConsole::clear() { ui->messagesWidget->clear(); + history.clear(); + historyPtr = 0; ui->lineEdit->clear(); ui->lineEdit->setFocus(); @@ -238,13 +336,10 @@ void RPCConsole::setNumConnections(int count) void RPCConsole::setNumBlocks(int count, int countOfPeers) { ui->numberOfBlocks->setText(QString::number(count)); - ui->totalBlocks->setText(QString::number(countOfPeers)); + // If there is no current countOfPeers available display N/A instead of 0, which can't ever be true + ui->totalBlocks->setText(countOfPeers == 0 ? tr("N/A") : QString::number(countOfPeers)); if(clientModel) - { - // If there is no current number available display N/A instead of 0, which can't ever be true - ui->totalBlocks->setText(clientModel->getNumBlocksOfPeers() == 0 ? tr("N/A") : QString::number(clientModel->getNumBlocksOfPeers())); ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString()); - } } void RPCConsole::on_lineEdit_returnPressed() @@ -285,16 +380,15 @@ void RPCConsole::browseHistory(int offset) void RPCConsole::startExecutor() { - QThread* thread = new QThread; + QThread *thread = new QThread; RPCExecutor *executor = new RPCExecutor(); executor->moveToThread(thread); - // Notify executor when thread started (in executor thread) - connect(thread, SIGNAL(started()), executor, SLOT(start())); // Replies from executor object must go to this object connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString))); // Requests from this object must go to executor 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 diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 86c2b01..d60bf5e 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -1,17 +1,22 @@ #include "sendcoinsdialog.h" #include "ui_sendcoinsdialog.h" + +#include "init.h" #include "walletmodel.h" +#include "addresstablemodel.h" #include "bitcoinunits.h" #include "addressbookpage.h" #include "optionsmodel.h" #include "sendcoinsentry.h" #include "guiutil.h" #include "askpassphrasedialog.h" +#include "coincontrol.h" +#include "coincontroldialog.h" #include -#include #include #include +#include SendCoinsDialog::SendCoinsDialog(QWidget *parent) : QDialog(parent), @@ -20,17 +25,53 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : { ui->setupUi(this); -#ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac +#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac ui->addButton->setIcon(QIcon()); ui->clearButton->setIcon(QIcon()); ui->sendButton->setIcon(QIcon()); #endif +#if QT_VERSION >= 0x040700 + /* Do not move this to the XML file, Qt before 4.7 will choke on it */ + ui->lineEditCoinControlChange->setPlaceholderText(tr("Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2)")); +#endif addEntry(); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + // Coin Control + ui->lineEditCoinControlChange->setFont(GUIUtil::bitcoinAddressFont()); + connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); + connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); + connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &))); + + // Coin Control: clipboard actions + QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); + QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this); + 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 low output"), this); + QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); + connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); + connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount())); + 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); + ui->labelCoinControlAmount->addAction(clipboardAmountAction); + ui->labelCoinControlFee->addAction(clipboardFeeAction); + ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); + ui->labelCoinControlBytes->addAction(clipboardBytesAction); + ui->labelCoinControlPriority->addAction(clipboardPriorityAction); + ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); + ui->labelCoinControlChange->addAction(clipboardChangeAction); + fNewRecipientAllowed = true; } @@ -51,6 +92,13 @@ void SendCoinsDialog::setModel(WalletModel *model) setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance()); connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64))); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + // Coin Control + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); + connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); + connect(model->getOptionsModel(), SIGNAL(transactionFeeChanged(qint64)), this, SLOT(coinControlUpdateLabels())); + ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures()); + coinControlUpdateLabels(); } } @@ -92,7 +140,11 @@ void SendCoinsDialog::on_sendButton_clicked() QStringList formatted; foreach(const SendCoinsRecipient &rcp, recipients) { +#if QT_VERSION < 0x050000 formatted.append(tr("%1 to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address)); +#else + formatted.append(tr("%1 to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), rcp.label.toHtmlEscaped(), rcp.address)); +#endif } fNewRecipientAllowed = false; @@ -116,12 +168,16 @@ void SendCoinsDialog::on_sendButton_clicked() return; } - WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients); + WalletModel::SendCoinsReturn sendstatus; + if (!model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + sendstatus = model->sendCoins(recipients); + else + sendstatus = model->sendCoins(recipients, CoinControlDialog::coinControl); switch(sendstatus.status) { case WalletModel::InvalidAddress: QMessageBox::warning(this, tr("Send Coins"), - tr("The recepient address is not valid, please recheck."), + tr("The recipient address is not valid, please recheck."), QMessageBox::Ok, QMessageBox::Ok); break; case WalletModel::InvalidAmount: @@ -147,7 +203,7 @@ void SendCoinsDialog::on_sendButton_clicked() break; case WalletModel::TransactionCreationFailed: QMessageBox::warning(this, tr("Send Coins"), - tr("Error: Transaction creation failed."), + tr("Error: Transaction creation failed!"), QMessageBox::Ok, QMessageBox::Ok); break; case WalletModel::TransactionCommitFailed: @@ -159,6 +215,8 @@ void SendCoinsDialog::on_sendButton_clicked() break; case WalletModel::OK: accept(); + CoinControlDialog::coinControl->UnSelectAll(); + coinControlUpdateLabels(); break; } fNewRecipientAllowed = true; @@ -169,7 +227,7 @@ void SendCoinsDialog::clear() // Remove entries until only one left while(ui->entries->count()) { - delete ui->entries->takeAt(0)->widget(); + ui->entries->takeAt(0)->widget()->deleteLater(); } addEntry(); @@ -194,6 +252,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry() entry->setModel(model); ui->entries->addWidget(entry); connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*))); + connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels())); updateRemoveEnabled(); @@ -201,7 +260,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry() entry->clear(); entry->setFocus(); ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint()); - QCoreApplication::instance()->processEvents(); + qApp->processEvents(); QScrollBar* bar = ui->scrollArea->verticalScrollBar(); if(bar) bar->setSliderPosition(bar->maximum()); @@ -221,11 +280,13 @@ void SendCoinsDialog::updateRemoveEnabled() } } setupTabChain(0); + + coinControlUpdateLabels(); } void SendCoinsDialog::removeEntry(SendCoinsEntry* entry) { - delete entry; + entry->deleteLater(); updateRemoveEnabled(); } @@ -244,6 +305,26 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) return ui->sendButton; } +void SendCoinsDialog::setAddress(const QString &address) +{ + SendCoinsEntry *entry = 0; + // Replace the first entry if it is still unused + if(ui->entries->count() == 1) + { + SendCoinsEntry *first = qobject_cast(ui->entries->itemAt(0)->widget()); + if(first->isClear()) + { + entry = first; + } + } + if(!entry) + { + entry = addEntry(); + } + + entry->setAddress(address); +} + void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) { if(!fNewRecipientAllowed) @@ -273,6 +354,9 @@ bool SendCoinsDialog::handleURI(const QString &uri) // URI has to be valid if (GUIUtil::parseBitcoinURI(uri, &rv)) { + CBitcoinAddress address(rv.address.toStdString()); + if (!address.IsValid()) + return false; pasteEntry(rv); return true; } @@ -299,3 +383,156 @@ void SendCoinsDialog::updateDisplayUnit() ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance())); } } + +// Coin Control: copy label "Quantity" to clipboard +void SendCoinsDialog::coinControlClipboardQuantity() +{ + GUIUtil::setClipboard(ui->labelCoinControlQuantity->text()); +} + +// Coin Control: copy label "Amount" to clipboard +void SendCoinsDialog::coinControlClipboardAmount() +{ + GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" "))); +} + +// Coin Control: copy label "Fee" to clipboard +void SendCoinsDialog::coinControlClipboardFee() +{ + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" "))); +} + +// Coin Control: copy label "After fee" to clipboard +void SendCoinsDialog::coinControlClipboardAfterFee() +{ + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" "))); +} + +// Coin Control: copy label "Bytes" to clipboard +void SendCoinsDialog::coinControlClipboardBytes() +{ + GUIUtil::setClipboard(ui->labelCoinControlBytes->text()); +} + +// Coin Control: copy label "Priority" to clipboard +void SendCoinsDialog::coinControlClipboardPriority() +{ + GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); +} + +// Coin Control: copy label "Low output" to clipboard +void SendCoinsDialog::coinControlClipboardLowOutput() +{ + GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text()); +} + +// Coin Control: copy label "Change" to clipboard +void SendCoinsDialog::coinControlClipboardChange() +{ + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" "))); +} + +// Coin Control: settings menu - coin control enabled/disabled by user +void SendCoinsDialog::coinControlFeatureChanged(bool checked) +{ + ui->frameCoinControl->setVisible(checked); + + if (!checked && model) // coin control features disabled + CoinControlDialog::coinControl->SetNull(); +} + +// Coin Control: button inputs -> show actual coin control dialog +void SendCoinsDialog::coinControlButtonClicked() +{ + CoinControlDialog dlg; + dlg.setModel(model); + dlg.exec(); + coinControlUpdateLabels(); +} + +// Coin Control: checkbox custom change address +void SendCoinsDialog::coinControlChangeChecked(int state) +{ + if (model) + { + if (state == Qt::Checked) + CoinControlDialog::coinControl->destChange = CBitcoinAddress(ui->lineEditCoinControlChange->text().toStdString()).Get(); + else + CoinControlDialog::coinControl->destChange = CNoDestination(); + } + + ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked)); + ui->labelCoinControlChangeLabel->setVisible((state == Qt::Checked)); +} + +// Coin Control: custom change address changed +void SendCoinsDialog::coinControlChangeEdited(const QString & text) +{ + if (model) + { + CoinControlDialog::coinControl->destChange = CBitcoinAddress(text.toStdString()).Get(); + + // label for the change address + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}"); + if (text.isEmpty()) + ui->labelCoinControlChangeLabel->setText(""); + else if (!CBitcoinAddress(text.toStdString()).IsValid()) + { + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); + ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address")); + } + else + { + QString associatedLabel = model->getAddressTableModel()->labelForAddress(text); + if (!associatedLabel.isEmpty()) + ui->labelCoinControlChangeLabel->setText(associatedLabel); + else + { + CPubKey pubkey; + CKeyID keyid; + CBitcoinAddress(text.toStdString()).GetKeyID(keyid); + if (model->getPubKey(keyid, pubkey)) + ui->labelCoinControlChangeLabel->setText(tr("(no label)")); + else + { + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); + ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); + } + } + } + } +} + +// Coin Control: update labels +void SendCoinsDialog::coinControlUpdateLabels() +{ + if (!model || !model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + return; + + // set pay amounts + CoinControlDialog::payAmounts.clear(); + for(int i = 0; i < ui->entries->count(); ++i) + { + SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if(entry) + CoinControlDialog::payAmounts.append(entry->getValue().amount); + } + + if (CoinControlDialog::coinControl->HasSelected()) + { + // actual coin control calculation + CoinControlDialog::updateLabels(model, this); + + // show coin control stats + ui->labelCoinControlAutomaticallySelected->hide(); + ui->widgetCoinControl->show(); + } + else + { + // hide coin control stats + ui->labelCoinControlAutomaticallySelected->show(); + ui->widgetCoinControl->hide(); + ui->labelCoinControlInsuffFunds->hide(); + } +} + diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index def2f83..d5fba9b 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -2,6 +2,7 @@ #define SENDCOINSDIALOG_H #include +#include namespace Ui { class SendCoinsDialog; @@ -25,10 +26,11 @@ public: void setModel(WalletModel *model); - /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907). + /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907). */ QWidget *setupTabChain(QWidget *prev); + void setAddress(const QString &address); void pasteEntry(const SendCoinsRecipient &rv); bool handleURI(const QString &uri); @@ -49,6 +51,19 @@ private slots: void on_sendButton_clicked(); void removeEntry(SendCoinsEntry* entry); void updateDisplayUnit(); + void coinControlFeatureChanged(bool); + void coinControlButtonClicked(); + void coinControlChangeChecked(int); + void coinControlChangeEdited(const QString &); + void coinControlUpdateLabels(); + void coinControlClipboardQuantity(); + void coinControlClipboardAmount(); + void coinControlClipboardFee(); + void coinControlClipboardAfterFee(); + void coinControlClipboardBytes(); + void coinControlClipboardPriority(); + void coinControlClipboardLowOutput(); + void coinControlClipboardChange(); }; #endif // SENDCOINSDIALOG_H diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 9dc53bc..08059e2 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -1,5 +1,6 @@ #include "sendcoinsentry.h" #include "ui_sendcoinsentry.h" + #include "guiutil.h" #include "bitcoinunits.h" #include "addressbookpage.h" @@ -17,7 +18,7 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) : { ui->setupUi(this); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC ui->payToLayout->setSpacing(4); #endif #if QT_VERSION >= 0x040700 @@ -72,6 +73,8 @@ void SendCoinsEntry::setModel(WalletModel *model) if(model && model->getOptionsModel()) connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged())); + clear(); } @@ -152,6 +155,12 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) ui->payAmount->setValue(value.amount); } +void SendCoinsEntry::setAddress(const QString &address) +{ + ui->payTo->setText(address); + ui->payAmount->setFocus(); +} + bool SendCoinsEntry::isClear() { return ui->payTo->text().isEmpty(); diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index db6cba0..bec25c1 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -26,8 +26,9 @@ public: bool isClear(); void setValue(const SendCoinsRecipient &value); + void setAddress(const QString &address); - /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907). + /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907). */ QWidget *setupTabChain(QWidget *prev); @@ -39,6 +40,7 @@ public slots: signals: void removeEntry(SendCoinsEntry *entry); + void payAmountChanged(); private slots: void on_deleteButton_clicked(); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index f8edbf8..7fa9bd2 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -10,11 +10,11 @@ #include "walletmodel.h" #include "wallet.h" +#include + #include #include -#include - SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SignVerifyMessageDialog), @@ -24,11 +24,11 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) : #if (QT_VERSION >= 0x040700) /* Do not move this to the XML file, Qt before 4.7 will choke on it */ - ui->addressIn_SM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); + ui->addressIn_SM->setPlaceholderText(tr("Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2)")); ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature")); - ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); - ui->signatureIn_VM->setPlaceholderText(tr("Enter Bitcoin signature")); + ui->addressIn_VM->setPlaceholderText(tr("Enter a CasinoCoin address (e.g. Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2)")); + ui->signatureIn_VM->setPlaceholderText(tr("Enter CasinoCoin signature")); #endif GUIUtil::setupAddressWidget(ui->addressIn_SM, this); @@ -55,13 +55,13 @@ void SignVerifyMessageDialog::setModel(WalletModel *model) this->model = model; } -void SignVerifyMessageDialog::setAddress_SM(QString address) +void SignVerifyMessageDialog::setAddress_SM(const QString &address) { ui->addressIn_SM->setText(address); ui->messageIn_SM->setFocus(); } -void SignVerifyMessageDialog::setAddress_VM(QString address) +void SignVerifyMessageDialog::setAddress_VM(const QString &address) { ui->addressIn_VM->setText(address); ui->messageIn_VM->setFocus(); @@ -126,7 +126,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() if (!ctx.isValid()) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel_SM->setText(tr("Wallet unlock was canceled.")); + ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled.")); return; } @@ -218,8 +218,8 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() ss << strMessageMagic; ss << ui->messageIn_VM->document()->toPlainText().toStdString(); - CKey key; - if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) + CPubKey pubkey; + if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig)) { ui->signatureIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); @@ -227,7 +227,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr)) + if (!(CBitcoinAddress(pubkey.GetID()) == addr)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("") + tr("Message verification failed.") + QString("")); diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index 5569c8b..558f24e 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -8,9 +8,6 @@ namespace Ui { } class WalletModel; -QT_BEGIN_NAMESPACE -QT_END_NAMESPACE - class SignVerifyMessageDialog : public QDialog { Q_OBJECT @@ -20,8 +17,8 @@ public: ~SignVerifyMessageDialog(); void setModel(WalletModel *model); - void setAddress_SM(QString address); - void setAddress_VM(QString address); + void setAddress_SM(const QString &address); + void setAddress_VM(const QString &address); void showTab_SM(bool fShow); void showTab_VM(bool fShow); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp new file mode 100644 index 0000000..758c864 --- /dev/null +++ b/src/qt/splashscreen.cpp @@ -0,0 +1,52 @@ +#include "splashscreen.h" +#include "clientversion.h" +#include "util.h" + +#include +#undef loop /* ugh, remove this when the #define loop is gone from util.h */ +#include + +SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) : + QSplashScreen(pixmap, f) +{ + // set reference point, paddings + int paddingLeftCol2 = 230; + int paddingTopCol2 = 376; + int line1 = 0; + int line2 = 13; + int line3 = 26; + + float fontFactor = 1.0; + + // define text to place + QString titleText = QString(QApplication::applicationName()).replace(QString("-testnet"), QString(""), Qt::CaseSensitive); // cut of testnet, place it as single object further down + QString versionText = QString("Version %1 ").arg(QString::fromStdString(FormatFullVersion())); + QString copyrightText1 = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin developers")); + QString copyrightText2 = QChar(0xA9)+QString(" 2013-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The CasinoCoin developers")); + + QString font = "Arial"; + + // load the bitmap for writing some text over it + QPixmap newPixmap; + if(GetBoolArg("-testnet")) { + newPixmap = QPixmap(":/images/splash_testnet"); + } + else { + newPixmap = QPixmap(":/images/splash"); + } + + QPainter pixPaint(&newPixmap); + pixPaint.setPen(QColor(255,255,255)); + + pixPaint.setFont(QFont(font, 9*fontFactor)); + pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line3,versionText); + + // draw copyright stuff +// pixPaint.setFont(QFont(font, 9*fontFactor)); +// pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line1,copyrightText1); +// pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line2,copyrightText2); + + pixPaint.end(); + + this->setPixmap(newPixmap); +} diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h new file mode 100644 index 0000000..6a6249d --- /dev/null +++ b/src/qt/splashscreen.h @@ -0,0 +1,16 @@ +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +#include + +/** class for the splashscreen with information of the running client + */ +class SplashScreen : public QSplashScreen +{ + Q_OBJECT + +public: + explicit SplashScreen(const QPixmap &pixmap = QPixmap(), Qt::WindowFlags f = 0); +}; + +#endif // SPLASHSCREEN_H diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 3ac31e6..3c7794b 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -6,6 +6,11 @@ // This is all you need to run all the tests int main(int argc, char *argv[]) { + bool fInvalid = false; + URITests test1; - QTest::qExec(&test1); + if (QTest::qExec(&test1) != 0) + fInvalid = true; + + return fInvalid; } diff --git a/src/qt/test/uritests.cpp b/src/qt/test/uritests.cpp index a281c39..bea5a3b 100644 --- a/src/qt/test/uritests.cpp +++ b/src/qt/test/uritests.cpp @@ -4,68 +4,59 @@ #include -/* -struct SendCoinsRecipient -{ - QString address; - QString label; - qint64 amount; -}; -*/ - void URITests::uriTests() { SendCoinsRecipient rv; QUrl uri; - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-dontexist=")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?req-dontexist=")); QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?dontexist=")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?dontexist=")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); QVERIFY(rv.label == QString()); QVERIFY(rv.amount == 0); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Wikipedia Example Address")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?label=Wikipedia Example Address")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); QVERIFY(rv.label == QString("Wikipedia Example Address")); QVERIFY(rv.amount == 0); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=0.001")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?amount=0.001")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); QVERIFY(rv.label == QString()); QVERIFY(rv.amount == 100000); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1.001")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?amount=1.001")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); QVERIFY(rv.label == QString()); QVERIFY(rv.amount == 100100000); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=100&label=Wikipedia Example")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?amount=100&label=Wikipedia Example")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); - QVERIFY(rv.amount == 10000000000); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); + QVERIFY(rv.amount == 10000000000LL); QVERIFY(rv.label == QString("Wikipedia Example")); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?message=Wikipedia Example Address")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); QVERIFY(rv.label == QString()); - QVERIFY(GUIUtil::parseBitcoinURI("bitcoin://175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address", &rv)); - QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(GUIUtil::parseBitcoinURI("casinocoin://LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?message=Wikipedia Example Address", &rv)); + QVERIFY(rv.address == QString("LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9")); QVERIFY(rv.label == QString()); // We currently don't implement the message parameter (ok, yea, we break spec...) - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-message=Wikipedia Example Address")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?req-message=Wikipedia Example Address")); QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?amount=1,000&label=Wikipedia Example")); QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000.0&label=Wikipedia Example")); + uri.setUrl(QString("casinocoin:LQDPC5rbjDB72fGFVHu4enYhxGAZuRiFh9?amount=1,000.0&label=Wikipedia Example")); QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); } diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 5007d21..e4dbf9c 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -2,19 +2,20 @@ #include "guiutil.h" #include "bitcoinunits.h" - #include "main.h" #include "wallet.h" #include "db.h" #include "ui_interface.h" #include "base58.h" +#include + QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) { if (!wtx.IsFinal()) { if (wtx.nLockTime < LOCKTIME_THRESHOLD) - return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime); + return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight + 1); else return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime)); } @@ -64,11 +65,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { strHTML += "" + tr("Source") + ": " + tr("Generated") + "
    "; } - else if (!wtx.mapValue["from"].empty()) + else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) { // Online transaction - if (!wtx.mapValue["from"].empty()) - strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
    "; + strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
    "; } else { @@ -104,7 +104,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // // To // - if (!wtx.mapValue["to"].empty()) + if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty()) { // Online transaction std::string strAddress = wtx.mapValue["to"]; @@ -160,7 +160,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) if (wallet->IsMine(txout)) continue; - if (wtx.mapValue["to"].empty()) + if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty()) { // Offline transaction CTxDestination address; @@ -209,15 +209,15 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // // Message // - if (!wtx.mapValue["message"].empty()) + if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty()) strHTML += "
    " + tr("Message") + ":
    " + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
    "; - if (!wtx.mapValue["comment"].empty()) + if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty()) strHTML += "
    " + tr("Comment") + ":
    " + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
    "; strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
    "; if (wtx.IsCoinBase()) - strHTML += "
    " + tr("Generated coins must mature 8 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.") + "
    "; + strHTML += "
    " + tr("Generated coins must mature 120 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.") + "
    "; // // Debug view @@ -235,8 +235,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML += "
    " + tr("Transaction") + ":
    "; strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true); - CTxDB txdb("r"); // To fetch source txouts - strHTML += "
    " + tr("Inputs") + ":"; strHTML += "
      "; @@ -246,8 +244,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { COutPoint prevout = txin.prevout; - CTransaction prev; - if(txdb.ReadDiskTx(prevout.hash, prev)) + CCoins prev; + if(pcoinsTip->GetCoins(prevout.hash, prev)) { if (prevout.n < prev.vout.size()) { diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index 2523f9a..cb0dda5 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -3,7 +3,6 @@ #include #include -#include class CWallet; class CWalletTx; @@ -13,8 +12,10 @@ class CWalletTx; class TransactionDesc: public QObject { Q_OBJECT + public: static QString toHTML(CWallet *wallet, CWalletTx &wtx); + private: TransactionDesc() {} diff --git a/src/qt/transactiondescdialog.h b/src/qt/transactiondescdialog.h index e86fb58..f7ceacb 100644 --- a/src/qt/transactiondescdialog.h +++ b/src/qt/transactiondescdialog.h @@ -6,6 +6,7 @@ namespace Ui { class TransactionDescDialog; } + QT_BEGIN_NAMESPACE class QModelIndex; QT_END_NAMESPACE diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 16fb4da..068e555 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -1,4 +1,5 @@ #include "transactionfilterproxy.h" + #include "transactiontablemodel.h" #include diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 8d6829d..1aea85a 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -8,6 +8,7 @@ class TransactionFilterProxy : public QSortFilterProxyModel { Q_OBJECT + public: explicit TransactionFilterProxy(QObject *parent = 0); @@ -23,7 +24,7 @@ public: void setDateRange(const QDateTime &from, const QDateTime &to); void setAddressPrefix(const QString &addrPrefix); /** - @note Type filter takes a bitfield created with TYPE() or ALL_TYPES + @note Type filter takes a bit field created with TYPE() or ALL_TYPES */ void setTypeFilter(quint32 modes); void setMinAmount(qint64 minimum); @@ -32,6 +33,7 @@ public: void setLimit(int limit); int rowCount(const QModelIndex &parent = QModelIndex()) const; + protected: bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const; @@ -42,11 +44,6 @@ private: quint32 typeFilter; qint64 minAmount; int limitRows; - -signals: - -public slots: - }; #endif // TRANSACTIONFILTERPROXY_H diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 1609736..40a5f73 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -9,18 +9,8 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx) { if (wtx.IsCoinBase()) { - // Don't show generated coin until confirmed by at least one block after it - // so we don't get the user's hopes up until it looks like it's probably accepted. - // - // It is not an error when generated blocks are not accepted. By design, - // some percentage of blocks, like 10% or more, will end up not accepted. - // This is the normal mechanism by which the network copes with latency. - // - // We display regular transactions right away before any confirmation - // because they can always get into some block eventually. Generated coins - // are special because if their block is not accepted, they are not valid. - // - if (wtx.GetDepthInMainChain() < 2) + // Ensures we show generated coins / mined transactions at depth 1 + if (!wtx.IsInMainChain()) { return false; } @@ -54,12 +44,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; - if (wtx.IsCoinBase()) - { - // Generated - sub.type = TransactionRecord::Generated; - } - else if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; @@ -71,6 +56,11 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } + if (wtx.IsCoinBase()) + { + // Generated + sub.type = TransactionRecord::Generated; + } parts.append(sub); } @@ -177,7 +167,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) if (wtx.nLockTime < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; - status.open_for = nBestHeight - wtx.nLockTime; + status.open_for = wtx.nLockTime - nBestHeight + 1; } else { diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index db06374..d760d47 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -14,8 +14,8 @@ class TransactionStatus { public: TransactionStatus(): - confirmed(false), sortKey(""), maturity(Mature), - matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1) + confirmed(false), sortKey(""), maturity(Mature), + matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1) { } enum Maturity @@ -47,7 +47,9 @@ public: @{*/ Status status; int64 depth; - int64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number of blocks */ + int64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number + of additional blocks that need to be mined before + finalization */ /**@}*/ /** Current number of blocks (to know whether cached status is still valid) */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index b3e001e..baf1e16 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -1,4 +1,5 @@ #include "transactiontablemodel.h" + #include "guiutil.h" #include "transactionrecord.h" #include "guiconstants.h" @@ -11,13 +12,11 @@ #include "wallet.h" #include "ui_interface.h" -#include #include #include #include #include #include -#include // Amount column is right-aligned it contains numbers static int column_alignments[] = { @@ -280,7 +279,7 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons switch(wtx->status.status) { case TransactionStatus::OpenUntilBlock: - status = tr("Open for %n block(s)","",wtx->status.open_for); + status = tr("Open for %n more block(s)","",wtx->status.open_for); break; case TransactionStatus::OpenUntilDate: status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for)); @@ -392,11 +391,11 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b return QString::fromStdString(wtx->address); case TransactionRecord::RecvWithAddress: case TransactionRecord::SendToAddress: + case TransactionRecord::Generated: return lookupAddress(wtx->address, tooltip); case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address); case TransactionRecord::SendToSelf: - case TransactionRecord::Generated: default: return tr("(n/a)"); } @@ -409,13 +408,13 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const { case TransactionRecord::RecvWithAddress: case TransactionRecord::SendToAddress: + case TransactionRecord::Generated: { QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address)); if(label.isEmpty()) return COLOR_BAREADDRESS; } break; case TransactionRecord::SendToSelf: - case TransactionRecord::Generated: return COLOR_BAREADDRESS; default: break; diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index fd321ce..6b2961c 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -14,6 +14,7 @@ class WalletModel; class TransactionTableModel : public QAbstractTableModel { Q_OBJECT + public: explicit TransactionTableModel(CWallet* wallet, WalletModel *parent = 0); ~TransactionTableModel(); @@ -55,6 +56,7 @@ public: QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; + private: CWallet* wallet; WalletModel *walletModel; @@ -81,5 +83,4 @@ public slots: friend class TransactionTablePriv; }; -#endif - +#endif // TRANSACTIONTABLEMODEL_H diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 1370a30..a43e29c 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -20,12 +20,9 @@ #include #include #include -#include #include #include #include -#include -#include #include #include @@ -38,7 +35,7 @@ TransactionView::TransactionView(QWidget *parent) : QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setContentsMargins(0,0,0,0); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC hlayout->setSpacing(5); hlayout->addSpacing(26); #else @@ -47,7 +44,7 @@ TransactionView::TransactionView(QWidget *parent) : #endif dateWidget = new QComboBox(this); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC dateWidget->setFixedWidth(121); #else dateWidget->setFixedWidth(120); @@ -62,7 +59,7 @@ TransactionView::TransactionView(QWidget *parent) : hlayout->addWidget(dateWidget); typeWidget = new QComboBox(this); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC typeWidget->setFixedWidth(121); #else typeWidget->setFixedWidth(120); @@ -91,7 +88,7 @@ TransactionView::TransactionView(QWidget *parent) : /* Do not move this to the XML file, Qt before 4.7 will choke on it */ amountWidget->setPlaceholderText(tr("Min amount")); #endif -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC amountWidget->setFixedWidth(97); #else amountWidget->setFixedWidth(100); @@ -110,7 +107,7 @@ TransactionView::TransactionView(QWidget *parent) : vlayout->setSpacing(0); int width = view->verticalScrollBar()->sizeHint().width(); // Cover scroll bar width with spacing -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC hlayout->addSpacing(width+2); #else hlayout->addSpacing(width); @@ -126,6 +123,7 @@ TransactionView::TransactionView(QWidget *parent) : QAction *copyAddressAction = new QAction(tr("Copy address"), this); QAction *copyLabelAction = new QAction(tr("Copy label"), this); QAction *copyAmountAction = new QAction(tr("Copy amount"), this); + QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); QAction *editLabelAction = new QAction(tr("Edit label"), this); QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); @@ -133,6 +131,7 @@ TransactionView::TransactionView(QWidget *parent) : contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); + contextMenu->addAction(copyTxIDAction); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); @@ -148,6 +147,7 @@ TransactionView::TransactionView(QWidget *parent) : connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } @@ -173,16 +173,15 @@ void TransactionView::setModel(WalletModel *model) transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder); transactionView->verticalHeader()->hide(); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Status, 23); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Date, 120); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Type, 120); - transactionView->horizontalHeader()->setResizeMode( - TransactionTableModel::ToAddress, QHeaderView::Stretch); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Amount, 100); + transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23); + transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120); + transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120); +#if QT_VERSION < 0x050000 + transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch); +#else + transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch); +#endif + transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100); } } @@ -205,7 +204,7 @@ void TransactionView::chooseDate(int idx) TransactionFilterProxy::MAX_DATE); break; case ThisWeek: { - // Find last monday + // Find last Monday QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1)); transactionProxyModel->setDateRange( QDateTime(startOfWeek), @@ -317,6 +316,11 @@ void TransactionView::copyAmount() GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole); } +void TransactionView::copyTxID() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole); +} + void TransactionView::editLabel() { if(!transactionView->selectionModel() ||!model) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 4ade3ec..bb41a83 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -22,6 +22,7 @@ QT_END_NAMESPACE class TransactionView : public QWidget { Q_OBJECT + public: explicit TransactionView(QWidget *parent = 0); @@ -65,6 +66,7 @@ private slots: void editLabel(); void copyLabel(); void copyAmount(); + void copyTxID(); signals: void doubleClicked(const QModelIndex&); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp new file mode 100644 index 0000000..dc074e8 --- /dev/null +++ b/src/qt/walletframe.cpp @@ -0,0 +1,161 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2013 + */ +#include "walletframe.h" +#include "bitcoingui.h" +#include "walletstack.h" +#include "walletview.h" + +#include +#include +#include + +WalletFrame::WalletFrame(BitcoinGUI *_gui) : + QFrame(_gui), + gui(_gui), + clientModel(0) +{ + // Leave HBox hook for adding a list view later + QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); + setContentsMargins(0,0,0,0); + walletStack = new WalletStack(this); + walletStack->setBitcoinGUI(gui); + walletFrameLayout->setContentsMargins(0,0,0,0); + walletFrameLayout->addWidget(walletStack); + + QLabel *noWallet = new QLabel(tr("No wallet has been loaded.")); + noWallet->setAlignment(Qt::AlignCenter); + walletStack->addWidget(noWallet); +} + +WalletFrame::~WalletFrame() +{ +} + +void WalletFrame::setClientModel(ClientModel *clientModel) +{ + this->clientModel = clientModel; + walletStack->setClientModel(clientModel); +} + +bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) +{ + return walletStack->addWallet(name, walletModel); +} + +bool WalletFrame::setCurrentWallet(const QString& name) +{ + // TODO: Check if valid name + walletStack->setCurrentWallet(name); + return true; +} + +void WalletFrame::removeAllWallets() +{ + walletStack->removeAllWallets(); +} + +bool WalletFrame::handleURI(const QString &uri) +{ + WalletView *walletView = currentWalletView(); + if (!walletView) + return false; + + return walletStack->handleURI(uri); +} + +void WalletFrame::showOutOfSyncWarning(bool fShow) +{ + if (!walletStack) { + QMessageBox box; + box.setText("walletStack is null"); + box.exec(); + return; + } + walletStack->showOutOfSyncWarning(fShow); +} + +void WalletFrame::gotoOverviewPage() +{ + walletStack->gotoOverviewPage(); +} + +void WalletFrame::gotoHistoryPage() +{ + walletStack->gotoHistoryPage(); +} + +void WalletFrame::gotoAddressBookPage() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletStack->gotoAddressBookPage(); +} + +void WalletFrame::gotoReceiveCoinsPage() +{ + walletStack->gotoReceiveCoinsPage(); +} + +void WalletFrame::gotoSendCoinsPage(QString addr) +{ + walletStack->gotoSendCoinsPage(addr); +} + +void WalletFrame::gotoSignMessageTab(QString addr) +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->gotoSignMessageTab(addr); +} + +void WalletFrame::gotoVerifyMessageTab(QString addr) +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->gotoVerifyMessageTab(addr); +} + +void WalletFrame::encryptWallet(bool status) +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->encryptWallet(status); +} + +void WalletFrame::backupWallet() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->backupWallet(); +} + +void WalletFrame::changePassphrase() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->changePassphrase(); +} + +void WalletFrame::unlockWallet() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->unlockWallet(); +} + +void WalletFrame::setEncryptionStatus() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletStack->setEncryptionStatus(); +} + +WalletView *WalletFrame::currentWalletView() +{ + return qobject_cast(walletStack->currentWidget()); +} + diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h new file mode 100644 index 0000000..74454b1 --- /dev/null +++ b/src/qt/walletframe.h @@ -0,0 +1,77 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2013 + */ +#ifndef WALLETFRAME_H +#define WALLETFRAME_H + +#include + +class BitcoinGUI; +class ClientModel; +class WalletModel; +class WalletStack; +class WalletView; + +class WalletFrame : public QFrame +{ + Q_OBJECT + +public: + explicit WalletFrame(BitcoinGUI *_gui = 0); + ~WalletFrame(); + + void setClientModel(ClientModel *clientModel); + + bool addWallet(const QString& name, WalletModel *walletModel); + bool setCurrentWallet(const QString& name); + + void removeAllWallets(); + + bool handleURI(const QString &uri); + + void showOutOfSyncWarning(bool fShow); + +private: + BitcoinGUI *gui; + ClientModel *clientModel; + WalletStack *walletStack; + + WalletView *currentWalletView(); + +public slots: + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(QString addr = ""); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Ask for passphrase to unlock wallet temporarily */ + void unlockWallet(); + + /** Set the encryption status as shown in the UI. + @param[in] status current encryption status + @see WalletModel::EncryptionStatus + */ + void setEncryptionStatus(); +}; + +#endif // WALLETFRAME_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 3568616..a95df81 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -36,8 +36,19 @@ WalletModel::~WalletModel() unsubscribeFromCoreSignals(); } -qint64 WalletModel::getBalance() const +qint64 WalletModel::getBalance(const CCoinControl *coinControl) const { + if (coinControl) + { + int64 nBalance = 0; + std::vector vCoins; + wallet->AvailableCoins(vCoins, true, coinControl); + BOOST_FOREACH(const COutput& out, vCoins) + nBalance += out.tx->vout[out.i].nValue; + + return nBalance; + } + return wallet->GetBalance(); } @@ -56,6 +67,8 @@ int WalletModel::getNumTransactions() const int numTransactions = 0; { LOCK(wallet->cs_wallet); + // the size of mapWallet contains the number of unique transaction IDs + // (e.g. payments to yourself generate 2 transactions, but both share the same transaction ID) numTransactions = wallet->mapWallet.size(); } return numTransactions; @@ -122,7 +135,7 @@ bool WalletModel::validateAddress(const QString &address) return addressParsed.IsValid(); } -WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList &recipients) +WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList &recipients, const CCoinControl *coinControl) { qint64 total = 0; QSet setAddress; @@ -154,12 +167,14 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList getBalance()) + int64 nBalance = getBalance(coinControl); + + if(total > nBalance) { return AmountExceedsBalance; } - if((total + nTransactionFee) > getBalance()) + if((total + nTransactionFee) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } @@ -179,17 +194,20 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListCreateTransaction(vecSend, wtx, keyChange, nFeeRequired); + std::string strFailReason; + bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason, coinControl); if(!fCreated) { - if((total + nFeeRequired) > wallet->GetBalance()) + if((total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); } + emit message(tr("Send Coins"), QString::fromStdString(strFailReason), + CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } - if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) + if(!uiInterface.ThreadSafeAskFee(nFeeRequired)) { return Aborted; } @@ -374,3 +392,72 @@ void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs) *this = rhs; rhs.relock = false; } + +bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const +{ + return wallet->GetPubKey(address, vchPubKeyOut); +} + +// returns a list of COutputs from COutPoints +void WalletModel::getOutputs(const std::vector& vOutpoints, std::vector& vOutputs) +{ + BOOST_FOREACH(const COutPoint& outpoint, vOutpoints) + { + if (!wallet->mapWallet.count(outpoint.hash)) continue; + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain()); + vOutputs.push_back(out); + } +} + +// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address) +void WalletModel::listCoins(std::map >& mapCoins) const +{ + std::vector vCoins; + wallet->AvailableCoins(vCoins); + + std::vector vLockedCoins; + wallet->ListLockedCoins(vLockedCoins); + + // add locked coins + BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins) + { + if (!wallet->mapWallet.count(outpoint.hash)) continue; + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain()); + vCoins.push_back(out); + } + + BOOST_FOREACH(const COutput& out, vCoins) + { + COutput cout = out; + + while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.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); + } + + CTxDestination address; + if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue; + mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out); + } +} + +bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const +{ + return wallet->IsLockedCoin(hash, n); +} + +void WalletModel::lockCoin(COutPoint& output) +{ + wallet->LockCoin(output); +} + +void WalletModel::unlockCoin(COutPoint& output) +{ + wallet->UnlockCoin(output); +} + +void WalletModel::listLockedCoins(std::vector& vOutpts) +{ + wallet->ListLockedCoins(vOutpts); +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 62558a4..4d61da9 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -2,6 +2,8 @@ #define WALLETMODEL_H #include +#include +#include #include "allocators.h" /* for SecureString */ @@ -9,6 +11,12 @@ class OptionsModel; class AddressTableModel; class TransactionTableModel; class CWallet; +class CKeyID; +class CPubKey; +class COutput; +class COutPoint; +class uint256; +class CCoinControl; QT_BEGIN_NAMESPACE class QTimer; @@ -26,6 +34,7 @@ public: class WalletModel : public QObject { Q_OBJECT + public: explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0); ~WalletModel(); @@ -53,8 +62,8 @@ public: OptionsModel *getOptionsModel(); AddressTableModel *getAddressTableModel(); TransactionTableModel *getTransactionTableModel(); - - qint64 getBalance() const; + + qint64 getBalance(const CCoinControl *coinControl=NULL) const; qint64 getUnconfirmedBalance() const; qint64 getImmatureBalance() const; int getNumTransactions() const; @@ -66,7 +75,7 @@ public: // Return status record for SendCoins, contains error id + information struct SendCoinsReturn { - SendCoinsReturn(StatusCode status, + SendCoinsReturn(StatusCode status=Aborted, qint64 fee=0, QString hex=QString()): status(status), fee(fee), hex(hex) {} @@ -76,7 +85,7 @@ public: }; // Send coins to a list of recipients - SendCoinsReturn sendCoins(const QList &recipients); + SendCoinsReturn sendCoins(const QList &recipients, const CCoinControl *coinControl=NULL); // Wallet encryption bool setWalletEncrypted(bool encrypted, const SecureString &passphrase); @@ -108,6 +117,15 @@ public: UnlockContext requestUnlock(); + bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; + void getOutputs(const std::vector& vOutpoints, std::vector& vOutputs); + void listCoins(std::map >& mapCoins) const; + + bool isLockedCoin(uint256 hash, unsigned int n) const; + void lockCoin(COutPoint& output); + void unlockCoin(COutPoint& output); + void listLockedCoins(std::vector& vOutpts); + private: CWallet *wallet; @@ -147,8 +165,8 @@ signals: // this means that the unlocking failed or was cancelled. void requireUnlock(); - // Asynchronous error notification - void error(const QString &title, const QString &message, bool modal); + // Asynchronous message notification + void message(const QString &title, const QString &message, unsigned int style); public slots: /* Wallet status might have changed */ @@ -161,5 +179,4 @@ public slots: void pollBalanceChanged(); }; - #endif // WALLETMODEL_H diff --git a/src/qt/walletstack.cpp b/src/qt/walletstack.cpp new file mode 100644 index 0000000..3576d55 --- /dev/null +++ b/src/qt/walletstack.cpp @@ -0,0 +1,161 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2013 + */ +#include "walletstack.h" +#include "walletview.h" +#include "bitcoingui.h" + +#include +#include + +WalletStack::WalletStack(QWidget *parent) : + QStackedWidget(parent), + gui(0), + clientModel(0), + bOutOfSync(true) +{ + setContentsMargins(0,0,0,0); +} + +WalletStack::~WalletStack() +{ +} + +bool WalletStack::addWallet(const QString& name, WalletModel *walletModel) +{ + if (!gui || !clientModel || mapWalletViews.count(name) > 0) + return false; + + WalletView *walletView = new WalletView(this, gui); + walletView->setBitcoinGUI(gui); + walletView->setClientModel(clientModel); + walletView->setWalletModel(walletModel); + walletView->showOutOfSyncWarning(bOutOfSync); + addWidget(walletView); + mapWalletViews[name] = walletView; + + // Ensure a walletView is able to show the main window + connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + + return true; +} + +bool WalletStack::removeWallet(const QString& name) +{ + if (mapWalletViews.count(name) == 0) return false; + WalletView *walletView = mapWalletViews.take(name); + removeWidget(walletView); + return true; +} + +void WalletStack::removeAllWallets() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + removeWidget(i.value()); + mapWalletViews.clear(); +} + +bool WalletStack::handleURI(const QString &uri) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (!walletView) return false; + + return walletView->handleURI(uri); +} + +void WalletStack::showOutOfSyncWarning(bool fShow) +{ + bOutOfSync = fShow; + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->showOutOfSyncWarning(fShow); +} + +void WalletStack::gotoOverviewPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoOverviewPage(); +} + +void WalletStack::gotoHistoryPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoHistoryPage(); +} + +void WalletStack::gotoAddressBookPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoAddressBookPage(); +} + +void WalletStack::gotoReceiveCoinsPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoReceiveCoinsPage(); +} + +void WalletStack::gotoSendCoinsPage(QString addr) +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoSendCoinsPage(addr); +} + +void WalletStack::gotoSignMessageTab(QString addr) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->gotoSignMessageTab(addr); +} + +void WalletStack::gotoVerifyMessageTab(QString addr) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->gotoVerifyMessageTab(addr); +} + +void WalletStack::encryptWallet(bool status) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->encryptWallet(status); +} + +void WalletStack::backupWallet() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->backupWallet(); +} + +void WalletStack::changePassphrase() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->changePassphrase(); +} + +void WalletStack::unlockWallet() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->unlockWallet(); +} + +void WalletStack::setEncryptionStatus() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->setEncryptionStatus(); +} + +void WalletStack::setCurrentWallet(const QString& name) +{ + if (mapWalletViews.count(name) == 0) return; + WalletView *walletView = mapWalletViews.value(name); + setCurrentWidget(walletView); + walletView->setEncryptionStatus(); +} diff --git a/src/qt/walletstack.h b/src/qt/walletstack.h new file mode 100644 index 0000000..506d595 --- /dev/null +++ b/src/qt/walletstack.h @@ -0,0 +1,103 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2013 + */ +#ifndef WALLETSTACK_H +#define WALLETSTACK_H + +#include +#include +#include + +class BitcoinGUI; +class TransactionTableModel; +class ClientModel; +class WalletModel; +class WalletView; +class TransactionView; +class OverviewPage; +class AddressBookPage; +class SendCoinsDialog; +class SignVerifyMessageDialog; +class Notificator; +class RPCConsole; + +class CWalletManager; + +QT_BEGIN_NAMESPACE +class QLabel; +class QModelIndex; +QT_END_NAMESPACE + +/* + WalletStack class. This class is a container for WalletView instances. It takes the place of centralWidget. + It was added to support multiple wallet functionality. It communicates with both the client and the + wallet models to give the user an up-to-date view of the current core state. It manages all the wallet views + it contains and updates them accordingly. + */ +class WalletStack : public QStackedWidget +{ + Q_OBJECT + +public: + explicit WalletStack(QWidget *parent = 0); + ~WalletStack(); + + void setBitcoinGUI(BitcoinGUI *gui) { this->gui = gui; } + + void setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; } + + bool addWallet(const QString& name, WalletModel *walletModel); + bool removeWallet(const QString& name); + + void removeAllWallets(); + + bool handleURI(const QString &uri); + + void showOutOfSyncWarning(bool fShow); + +private: + BitcoinGUI *gui; + ClientModel *clientModel; + QMap mapWalletViews; + + bool bOutOfSync; + +public slots: + void setCurrentWallet(const QString& name); + + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(QString addr = ""); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Ask for passphrase to unlock wallet temporarily */ + void unlockWallet(); + + /** Set the encryption status as shown in the UI. + @param[in] status current encryption status + @see WalletModel::EncryptionStatus + */ + void setEncryptionStatus(); +}; + +#endif // WALLETSTACK_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp new file mode 100644 index 0000000..dd2034c --- /dev/null +++ b/src/qt/walletview.cpp @@ -0,0 +1,275 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2013 + */ +#include "walletview.h" +#include "bitcoingui.h" +#include "transactiontablemodel.h" +#include "addressbookpage.h" +#include "sendcoinsdialog.h" +#include "signverifymessagedialog.h" +#include "clientmodel.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "transactionview.h" +#include "overviewpage.h" +#include "askpassphrasedialog.h" +#include "ui_interface.h" + +#include +#include +#include +#if QT_VERSION < 0x050000 +#include +#else +#include +#endif +#include +#include + +WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui): + QStackedWidget(parent), + gui(_gui), + clientModel(0), + walletModel(0) +{ + // Create tabs + overviewPage = new OverviewPage(); + + transactionsPage = new QWidget(this); + QVBoxLayout *vbox = new QVBoxLayout(); + QHBoxLayout *hbox_buttons = new QHBoxLayout(); + transactionView = new TransactionView(this); + vbox->addWidget(transactionView); + QPushButton *exportButton = new QPushButton(tr("&Export"), this); + exportButton->setToolTip(tr("Export the data in the current tab to a file")); +#ifndef Q_OS_MAC // Icons on push buttons are very uncommon on Mac + exportButton->setIcon(QIcon(":/icons/export")); +#endif + hbox_buttons->addStretch(); + hbox_buttons->addWidget(exportButton); + vbox->addLayout(hbox_buttons); + transactionsPage->setLayout(vbox); + + addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); + + receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); + + sendCoinsPage = new SendCoinsDialog(gui); + + signVerifyMessageDialog = new SignVerifyMessageDialog(gui); + + addWidget(overviewPage); + addWidget(transactionsPage); + addWidget(addressBookPage); + addWidget(receiveCoinsPage); + addWidget(sendCoinsPage); + + // Clicking on a transaction on the overview page simply sends you to transaction history page + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage())); + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); + + // Double-clicking on a transaction on the transaction history page shows details + connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); + + // Clicking on "Send Coins" in the address book sends you to the send coins tab + connect(addressBookPage, SIGNAL(sendCoins(QString)), this, SLOT(gotoSendCoinsPage(QString))); + // Clicking on "Verify Message" in the address book opens the verify message tab in the Sign/Verify Message dialog + connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString))); + // Clicking on "Sign Message" in the receive coins page opens the sign message tab in the Sign/Verify Message dialog + connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); + // Clicking on "Export" allows to export the transaction list + connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked())); + + gotoOverviewPage(); +} + +WalletView::~WalletView() +{ +} + +void WalletView::setBitcoinGUI(BitcoinGUI *gui) +{ + this->gui = gui; +} + +void WalletView::setClientModel(ClientModel *clientModel) +{ + this->clientModel = clientModel; + if (clientModel) + { + overviewPage->setClientModel(clientModel); + addressBookPage->setOptionsModel(clientModel->getOptionsModel()); + receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); + } +} + +void WalletView::setWalletModel(WalletModel *walletModel) +{ + this->walletModel = walletModel; + if (walletModel) + { + // Receive and report messages from wallet thread + connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); + + // Put transaction list in tabs + transactionView->setModel(walletModel); + overviewPage->setWalletModel(walletModel); + addressBookPage->setModel(walletModel->getAddressTableModel()); + receiveCoinsPage->setModel(walletModel->getAddressTableModel()); + sendCoinsPage->setModel(walletModel); + signVerifyMessageDialog->setModel(walletModel); + + setEncryptionStatus(); + connect(walletModel, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + + // Balloon pop-up for new transaction + connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(incomingTransaction(QModelIndex,int,int))); + + // Ask for passphrase if needed + connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + } +} + +void WalletView::incomingTransaction(const QModelIndex& parent, int start, int /*end*/) +{ + // Prevent balloon-spam when initial block download is in progress + if(!walletModel || !clientModel || clientModel->inInitialBlockDownload()) + return; + + TransactionTableModel *ttm = walletModel->getTransactionTableModel(); + + QString date = ttm->index(start, TransactionTableModel::Date, parent).data().toString(); + qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent).data(Qt::EditRole).toULongLong(); + QString type = ttm->index(start, TransactionTableModel::Type, parent).data().toString(); + QString address = ttm->index(start, TransactionTableModel::ToAddress, parent).data().toString(); + + gui->incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address); +} + +void WalletView::gotoOverviewPage() +{ + gui->getOverviewAction()->setChecked(true); + setCurrentWidget(overviewPage); +} + +void WalletView::gotoHistoryPage() +{ + gui->getHistoryAction()->setChecked(true); + setCurrentWidget(transactionsPage); +} + +void WalletView::gotoAddressBookPage() +{ + gui->getAddressBookAction()->setChecked(true); + setCurrentWidget(addressBookPage); +} + +void WalletView::gotoReceiveCoinsPage() +{ + gui->getReceiveCoinsAction()->setChecked(true); + setCurrentWidget(receiveCoinsPage); +} + +void WalletView::gotoSendCoinsPage(QString addr) +{ + gui->getSendCoinsAction()->setChecked(true); + setCurrentWidget(sendCoinsPage); + + if (!addr.isEmpty()) + sendCoinsPage->setAddress(addr); +} + +void WalletView::gotoSignMessageTab(QString addr) +{ + // call show() in showTab_SM() + signVerifyMessageDialog->showTab_SM(true); + + if (!addr.isEmpty()) + signVerifyMessageDialog->setAddress_SM(addr); +} + +void WalletView::gotoVerifyMessageTab(QString addr) +{ + // call show() in showTab_VM() + signVerifyMessageDialog->showTab_VM(true); + + if (!addr.isEmpty()) + signVerifyMessageDialog->setAddress_VM(addr); +} + +bool WalletView::handleURI(const QString& strURI) +{ + // URI has to be valid + if (sendCoinsPage->handleURI(strURI)) + { + gotoSendCoinsPage(); + emit showNormalIfMinimized(); + return true; + } + else + return false; +} + +void WalletView::showOutOfSyncWarning(bool fShow) +{ + overviewPage->showOutOfSyncWarning(fShow); +} + +void WalletView::setEncryptionStatus() +{ + gui->setEncryptionStatus(walletModel->getEncryptionStatus()); +} + +void WalletView::encryptWallet(bool status) +{ + if(!walletModel) + return; + AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt : AskPassphraseDialog::Decrypt, this); + dlg.setModel(walletModel); + dlg.exec(); + + setEncryptionStatus(); +} + +void WalletView::backupWallet() +{ +#if QT_VERSION < 0x050000 + QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); +#else + QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); +#endif + QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); + if (!filename.isEmpty()) { + if (!walletModel->backupWallet(filename)) { + gui->message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."), + CClientUIInterface::MSG_ERROR); + } + else + gui->message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."), + CClientUIInterface::MSG_INFORMATION); + } +} + +void WalletView::changePassphrase() +{ + AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); + dlg.setModel(walletModel); + dlg.exec(); +} + +void WalletView::unlockWallet() +{ + if(!walletModel) + return; + // Unlock wallet when requested by wallet model + if (walletModel->getEncryptionStatus() == WalletModel::Locked) + { + AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this); + dlg.setModel(walletModel); + dlg.exec(); + } +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h new file mode 100644 index 0000000..6ad5180 --- /dev/null +++ b/src/qt/walletview.h @@ -0,0 +1,108 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2013 + */ +#ifndef WALLETVIEW_H +#define WALLETVIEW_H + +#include + +class BitcoinGUI; +class ClientModel; +class WalletModel; +class TransactionView; +class OverviewPage; +class AddressBookPage; +class SendCoinsDialog; +class SignVerifyMessageDialog; +class RPCConsole; + +QT_BEGIN_NAMESPACE +class QLabel; +class QModelIndex; +QT_END_NAMESPACE + +/* + WalletView class. This class represents the view to a single wallet. + It was added to support multiple wallet functionality. Each wallet gets its own WalletView instance. + It communicates with both the client and the wallet models to give the user an up-to-date view of the + current core state. +*/ +class WalletView : public QStackedWidget +{ + Q_OBJECT + +public: + explicit WalletView(QWidget *parent, BitcoinGUI *_gui); + ~WalletView(); + + void setBitcoinGUI(BitcoinGUI *gui); + /** Set the client model. + The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. + */ + void setClientModel(ClientModel *clientModel); + /** Set the wallet model. + The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending + functionality. + */ + void setWalletModel(WalletModel *walletModel); + + bool handleURI(const QString &uri); + + void showOutOfSyncWarning(bool fShow); + +private: + BitcoinGUI *gui; + ClientModel *clientModel; + WalletModel *walletModel; + + OverviewPage *overviewPage; + QWidget *transactionsPage; + AddressBookPage *addressBookPage; + AddressBookPage *receiveCoinsPage; + SendCoinsDialog *sendCoinsPage; + SignVerifyMessageDialog *signVerifyMessageDialog; + + TransactionView *transactionView; + +public slots: + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(QString addr = ""); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Show incoming transaction notification for new transactions. + + The new items are those between start and end inclusive, under the given parent item. + */ + void incomingTransaction(const QModelIndex& parent, int start, int /*end*/); + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Ask for passphrase to unlock wallet temporarily */ + void unlockWallet(); + + void setEncryptionStatus(); + +signals: + /** Signal that we want to show the main window */ + void showNormalIfMinimized(); +}; + +#endif // WALLETVIEW_H diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp new file mode 100644 index 0000000..9d58133 --- /dev/null +++ b/src/rpcblockchain.cpp @@ -0,0 +1,270 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "bitcoinrpc.h" + +using namespace json_spirit; +using namespace std; + +void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out); + +double GetDifficulty(const CBlockIndex* blockindex) +{ + // Floating point number that is a multiple of the minimum difficulty, + // minimum difficulty = 1.0. + if (blockindex == NULL) + { + if (pindexBest == NULL) + return 1.0; + else + blockindex = pindexBest; + } + + int nShift = (blockindex->nBits >> 24) & 0xff; + + double dDiff = + (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff); + + while (nShift < 29) + { + dDiff *= 256.0; + nShift++; + } + while (nShift > 29) + { + dDiff /= 256.0; + nShift--; + } + + return dDiff; +} + + +Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) +{ + Object result; + result.push_back(Pair("hash", block.GetHash().GetHex())); + CMerkleTx txGen(block.vtx[0]); + txGen.SetMerkleBranch(&block); + result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); + result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); + result.push_back(Pair("height", blockindex->nHeight)); + result.push_back(Pair("version", block.nVersion)); + result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); + Array txs; + BOOST_FOREACH(const CTransaction&tx, block.vtx) + txs.push_back(tx.GetHash().GetHex()); + result.push_back(Pair("tx", txs)); + result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); + result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); + result.push_back(Pair("bits", HexBits(block.nBits))); + result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + + if (blockindex->pprev) + result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); + if (blockindex->pnext) + result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); + return result; +} + + +Value getblockcount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getblockcount\n" + "Returns the number of blocks in the longest block chain."); + + return nBestHeight; +} + +Value getbestblockhash(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getbestblockhash\n" + "Returns the hash of the best (tip) block in the longest block chain."); + + return hashBestChain.GetHex(); +} + +Value getdifficulty(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getdifficulty\n" + "Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); + + return GetDifficulty(); +} + + +Value settxfee(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "settxfee \n" + " is a real and is rounded to the nearest 0.00000001"); + + // Amount + int64 nAmount = 0; + if (params[0].get_real() != 0.0) + nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts + + nTransactionFee = nAmount; + return true; +} + +Value getrawmempool(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getrawmempool\n" + "Returns all transaction ids in memory pool."); + + vector vtxid; + mempool.queryHashes(vtxid); + + Array a; + BOOST_FOREACH(const uint256& hash, vtxid) + a.push_back(hash.ToString()); + + return a; +} + +Value getblockhash(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getblockhash \n" + "Returns hash of block in best-block-chain at ."); + + int nHeight = params[0].get_int(); + if (nHeight < 0 || nHeight > nBestHeight) + throw runtime_error("Block number out of range."); + + CBlockIndex* pblockindex = FindBlockByHeight(nHeight); + return pblockindex->phashBlock->GetHex(); +} + +Value getblock(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblock [verbose=true]\n" + "If verbose is false, returns a string that is serialized, hex-encoded data for block .\n" + "If verbose is true, returns an Object with information about block ." + ); + + std::string strHash = params[0].get_str(); + uint256 hash(strHash); + + bool fVerbose = true; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + block.ReadFromDisk(pblockindex); + + if (!fVerbose) + { + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << block; + std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); + return strHex; + } + + return blockToJSON(block, pblockindex); +} + +Value gettxoutsetinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "gettxoutsetinfo\n" + "Returns statistics about the unspent transaction output set."); + + Object ret; + + CCoinsStats stats; + if (pcoinsTip->GetStats(stats)) { + ret.push_back(Pair("height", (boost::int64_t)stats.nHeight)); + ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); + ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions)); + ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs)); + ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize)); + ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex())); + ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); + } + return ret; +} + +Value gettxout(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error( + "gettxout [includemempool=true]\n" + "Returns details about an unspent transaction output."); + + Object ret; + + std::string strHash = params[0].get_str(); + uint256 hash(strHash); + int n = params[1].get_int(); + bool fMempool = true; + if (params.size() > 2) + fMempool = params[2].get_bool(); + + CCoins coins; + if (fMempool) { + LOCK(mempool.cs); + CCoinsViewMemPool view(*pcoinsTip, mempool); + if (!view.GetCoins(hash, coins)) + return Value::null; + mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool + } else { + if (!pcoinsTip->GetCoins(hash, coins)) + return Value::null; + } + if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) + return Value::null; + + ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex())); + if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT) + ret.push_back(Pair("confirmations", 0)); + else + ret.push_back(Pair("confirmations", pcoinsTip->GetBestBlock()->nHeight - coins.nHeight + 1)); + ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); + Object o; + ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o); + ret.push_back(Pair("scriptPubKey", o)); + ret.push_back(Pair("version", coins.nVersion)); + ret.push_back(Pair("coinbase", coins.fCoinBase)); + + return ret; +} + +Value verifychain(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "verifychain [check level] [num blocks]\n" + "Verifies blockchain database."); + + int nCheckLevel = GetArg("-checklevel", 3); + int nCheckDepth = GetArg("-checkblocks", 288); + if (params.size() > 0) + nCheckLevel = params[0].get_int(); + if (params.size() > 1) + nCheckDepth = params[1].get_int(); + + return VerifyDB(nCheckLevel, nCheckDepth); +} + diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 0f6f55b..42d107c 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -1,6 +1,4 @@ // Copyright (c) 2009-2012 Bitcoin Developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -36,36 +34,42 @@ public: Value importprivkey(const Array& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( - "importprivkey [label]\n" + "importprivkey [label] [rescan=true]\n" "Adds a private key (as returned by dumpprivkey) to your wallet."); string strSecret = params[0].get_str(); string strLabel = ""; if (params.size() > 1) strLabel = params[1].get_str(); + + // Whether to perform rescan after import + bool fRescan = true; + if (params.size() > 2) + fRescan = params[2].get_bool(); + CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(strSecret); - if (!fGood) throw JSONRPCError(-5,"Invalid private key"); + if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - CKey key; - bool fCompressed; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); - CKeyID vchAddress = key.GetPubKey().GetID(); + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + CKeyID vchAddress = pubkey.GetID(); { LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->MarkDirty(); pwalletMain->SetAddressBookName(vchAddress, strLabel); - if (!pwalletMain->AddKey(key)) - throw JSONRPCError(-4,"Error adding key to wallet"); + if (!pwalletMain->AddKeyPubKey(key, pubkey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); - pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); - pwalletMain->ReacceptWalletTransactions(); + if (fRescan) { + pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); + pwalletMain->ReacceptWalletTransactions(); + } } return Value::null; @@ -75,19 +79,18 @@ Value dumpprivkey(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( - "dumpprivkey \n" - "Reveals the private key corresponding to ."); + "dumpprivkey \n" + "Reveals the private key corresponding to ."); string strAddress = params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) - throw JSONRPCError(-5, "Invalid CasinoCoin address"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid CasinoCoin address"); CKeyID keyID; if (!address.GetKeyID(keyID)) - throw JSONRPCError(-3, "Address does not refer to a key"); - CSecret vchSecret; - bool fCompressed; - if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed)) - throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known"); - return CBitcoinSecret(vchSecret, fCompressed).ToString(); + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + CKey vchSecret; + if (!pwalletMain->GetKey(keyID, vchSecret)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); + return CBitcoinSecret(vchSecret).ToString(); } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp new file mode 100644 index 0000000..3b899fc --- /dev/null +++ b/src/rpcmining.cpp @@ -0,0 +1,588 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "db.h" +#include "init.h" +#include "bitcoinrpc.h" + +using namespace json_spirit; +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. +// If 'height' is nonnegative, compute the estimate at the time when a given block was found. +Value GetNetworkHashPS(int lookup, int height) { + CBlockIndex *pb = pindexBest; + + if (height >= 0 && height < nBestHeight) + pb = FindBlockByHeight(height); + + if (pb == NULL || !pb->nHeight) + return 0; + + // If lookup is -1, then use blocks since last difficulty change. + if (lookup <= 0) + lookup = pb->nHeight % 2016 + 1; + + // If lookup is larger than chain, then set it to chain length. + if (lookup > pb->nHeight) + lookup = pb->nHeight; + + CBlockIndex *pb0 = pb; + int64 minTime = pb0->GetBlockTime(); + int64 maxTime = minTime; + for (int i = 0; i < lookup; i++) { + pb0 = pb0->pprev; + int64 time = pb0->GetBlockTime(); + minTime = std::min(time, minTime); + maxTime = std::max(time, maxTime); + } + + // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception. + if (minTime == maxTime) + return 0; + + uint256 workDiff = pb->nChainWork - pb0->nChainWork; + int64 timeDiff = maxTime - minTime; + + return (boost::int64_t)(workDiff.getdouble() / timeDiff); +} + +Value getnetworkhashps(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getnetworkhashps [blocks] [height]\n" + "Returns the estimated network hashes per second based on the last 120 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."); + + return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); +} + + +// Key used by getwork/getblocktemplate miners. +// Allocated in InitRPCMining, free'd in ShutdownRPCMining +static CReserveKey* pMiningKey = NULL; + +void InitRPCMining() +{ + if (!pwalletMain) + return; + + // getwork/getblocktemplate mining rewards paid here: + pMiningKey = new CReserveKey(pwalletMain); +} + +void ShutdownRPCMining() +{ + if (!pMiningKey) + return; + + delete pMiningKey; pMiningKey = NULL; +} + +Value getgenerate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getgenerate\n" + "Returns true or false."); + + if (!pMiningKey) + return false; + + return GetBoolArg("-gen"); +} + + +Value setgenerate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setgenerate [genproclimit]\n" + " is true or false to turn generation on or off.\n" + "Generation is limited to [genproclimit] processors, -1 is unlimited."); + + bool fGenerate = true; + if (params.size() > 0) + fGenerate = params[0].get_bool(); + + if (params.size() > 1) + { + int nGenProcLimit = params[1].get_int(); + mapArgs["-genproclimit"] = itostr(nGenProcLimit); + if (nGenProcLimit == 0) + fGenerate = false; + } + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + + assert(pwalletMain != NULL); + GenerateBitcoins(fGenerate, pwalletMain); + return Value::null; +} + + +Value gethashespersec(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "gethashespersec\n" + "Returns a recent hashes per second performance measurement while generating."); + + if (GetTimeMillis() - nHPSTimerStart > 8000) + return (boost::int64_t)0; + return (boost::int64_t)dHashesPerSec; +} + + +Value getmininginfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getmininginfo\n" + "Returns an object containing mining-related information."); + + Object obj; + obj.push_back(Pair("blocks", (int)nBestHeight)); + obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); + 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("generate", GetBoolArg("-gen"))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); + obj.push_back(Pair("hashespersec", gethashespersec(params, false))); + obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); + obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); + obj.push_back(Pair("testnet", fTestNet)); + return obj; +} + + +Value getworkex(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getworkex [data, coinbase]\n" + "If [data, coinbase] is not specified, returns extended work data.\n" + ); + + if (vNodes.empty()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "CasinoCoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "CasinoCoin is downloading blocks..."); + + typedef map > mapNewBlock_t; + static mapNewBlock_t mapNewBlock; // FIXME: thread safety + static vector vNewBlockTemplate; + static CReserveKey reservekey(pwalletMain); + + if (params.size() == 0) + { + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlockTemplate* pblocktemplate; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) + { + if (pindexPrev != pindexBest) + { + // Deallocate old blocks since they're obsolete now + mapNewBlock.clear(); + BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate) + delete pblocktemplate; + vNewBlockTemplate.clear(); + } + + // Clear pindexPrev so future getworks make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrevNew = pindexBest; + nStart = GetTime(); + + // Create new block + pblocktemplate = CreateNewBlockWithKey(*pMiningKey); + if (!pblocktemplate) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + vNewBlockTemplate.push_back(pblocktemplate); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + // Update nExtraNonce + static unsigned int nExtraNonce = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + // Save + mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); + + // Pre-build hash buffers + char pmidstate[32]; + char pdata[128]; + char phash1[64]; + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + CTransaction coinbaseTx = pblock->vtx[0]; + std::vector merkle = pblock->GetMerkleBranch(0); + + Object result; + result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); + result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << coinbaseTx; + result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end()))); + + Array merkle_arr; + + BOOST_FOREACH(uint256 merkleh, merkle) { + printf("%s\n", merkleh.ToString().c_str()); + merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh))); + } + + result.push_back(Pair("merkle", merkle_arr)); + + return result; + } + else + { + // Parse parameters + vector vchData = ParseHex(params[0].get_str()); + vector coinbase; + + if(params.size() == 2) + coinbase = ParseHex(params[1].get_str()); + + if (vchData.size() != 128) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); + + CBlock* pdata = (CBlock*)&vchData[0]; + + // Byte reverse + for (int i = 0; i < 128/4; i++) + ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); + + // Get saved block + if (!mapNewBlock.count(pdata->hashMerkleRoot)) + return false; + CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; + + pblock->nTime = pdata->nTime; + pblock->nNonce = pdata->nNonce; + + if(coinbase.size() == 0) + pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; + else + CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; + + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + return CheckWork(pblock, *pwalletMain, reservekey); + } +} + + +Value getwork(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getwork [data]\n" + "If [data] is not specified, returns formatted hash data to work on:\n" + " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated + " \"data\" : block data\n" + " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated + " \"target\" : little endian hash target\n" + "If [data] is specified, tries to solve the block and returns true if it was successful."); + + if (vNodes.empty()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "CasinoCoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "CasinoCoin is downloading blocks..."); + + typedef map > mapNewBlock_t; + static mapNewBlock_t mapNewBlock; // FIXME: thread safety + static vector vNewBlockTemplate; + + if (params.size() == 0) + { + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlockTemplate* pblocktemplate; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) + { + if (pindexPrev != pindexBest) + { + // Deallocate old blocks since they're obsolete now + mapNewBlock.clear(); + BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate) + delete pblocktemplate; + vNewBlockTemplate.clear(); + } + + // Clear pindexPrev so future getworks make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrevNew = pindexBest; + nStart = GetTime(); + + // Create new block + pblocktemplate = CreateNewBlockWithKey(*pMiningKey); + if (!pblocktemplate) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + vNewBlockTemplate.push_back(pblocktemplate); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + // Update nExtraNonce + static unsigned int nExtraNonce = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + // Save + mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); + + // Pre-build hash buffers + char pmidstate[32]; + char pdata[128]; + char phash1[64]; + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + Object result; + result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated + result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); + result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated + result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); + return result; + } + else + { + // Parse parameters + vector vchData = ParseHex(params[0].get_str()); + if (vchData.size() != 128) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); + CBlock* pdata = (CBlock*)&vchData[0]; + + // Byte reverse + for (int i = 0; i < 128/4; i++) + ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); + + // Get saved block + if (!mapNewBlock.count(pdata->hashMerkleRoot)) + return false; + CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; + + pblock->nTime = pdata->nTime; + pblock->nNonce = pdata->nNonce; + pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + assert(pwalletMain != NULL); + return CheckWork(pblock, *pwalletMain, *pMiningKey); + } +} + + +Value getblocktemplate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getblocktemplate [params]\n" + "Returns data needed to construct a block to work on:\n" + " \"version\" : block version\n" + " \"previousblockhash\" : hash of current highest block\n" + " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n" + " \"coinbaseaux\" : data that should be included in coinbase\n" + " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" + " \"target\" : hash target\n" + " \"mintime\" : minimum timestamp appropriate for next block\n" + " \"curtime\" : current timestamp\n" + " \"mutable\" : list of ways the block template may be changed\n" + " \"noncerange\" : range of valid nonces\n" + " \"sigoplimit\" : limit of sigops in blocks\n" + " \"sizelimit\" : limit of block size\n" + " \"bits\" : compressed target of next block\n" + " \"height\" : height of the next block\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); + + std::string strMode = "template"; + if (params.size() > 0) + { + const Object& oparam = params[0].get_obj(); + const Value& modeval = find_value(oparam, "mode"); + if (modeval.type() == str_type) + strMode = modeval.get_str(); + else if (modeval.type() == null_type) + { + /* Do nothing */ + } + else + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + } + + if (strMode != "template") + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + + if (vNodes.empty()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "CasinoCoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "CasinoCoin is downloading blocks..."); + + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlockTemplate* pblocktemplate; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + { + // Clear pindexPrev so future calls make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrevNew = pindexBest; + nStart = GetTime(); + + // Create new block + if(pblocktemplate) + { + delete pblocktemplate; + pblocktemplate = NULL; + } + CScript scriptDummy = CScript() << OP_TRUE; + pblocktemplate = CreateNewBlock(scriptDummy); + if (!pblocktemplate) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + Array transactions; + map setTxIndex; + int i = 0; + BOOST_FOREACH (CTransaction& tx, pblock->vtx) + { + uint256 txHash = tx.GetHash(); + setTxIndex[txHash] = i++; + + if (tx.IsCoinBase()) + continue; + + Object entry; + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << tx; + entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); + + entry.push_back(Pair("hash", txHash.GetHex())); + + Array deps; + BOOST_FOREACH (const CTxIn &in, tx.vin) + { + if (setTxIndex.count(in.prevout.hash)) + deps.push_back(setTxIndex[in.prevout.hash]); + } + entry.push_back(Pair("depends", deps)); + + int index_in_template = i - 1; + entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); + entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); + + transactions.push_back(entry); + } + + Object aux; + aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + static Array aMutable; + if (aMutable.empty()) + { + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); + } + + Object result; + result.push_back(Pair("version", pblock->nVersion)); + 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("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)); + result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); + result.push_back(Pair("curtime", (int64_t)pblock->nTime)); + result.push_back(Pair("bits", HexBits(pblock->nBits))); + result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); + + return result; +} + +Value submitblock(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "submitblock [optional-params-obj]\n" + "[optional-params-obj] parameter is currently ignored.\n" + "Attempts to submit new block to network.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); + + vector blockData(ParseHex(params[0].get_str())); + CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION); + CBlock pblock; + try { + ssBlock >> pblock; + } + catch (std::exception &e) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + } + + CValidationState state; + bool fAccepted = ProcessBlock(state, NULL, &pblock); + if (!fAccepted) + return "rejected"; // TODO: report validation state + + return Value::null; +} diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index c716fb4..1228cb4 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -1,6 +1,4 @@ // Copyright (c) 2009-2012 Bitcoin Developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -53,17 +51,158 @@ Value getpeerinfo(const Array& params, bool fHelp) obj.push_back(Pair("services", strprintf("%08"PRI64x, stats.nServices))); obj.push_back(Pair("lastsend", (boost::int64_t)stats.nLastSend)); obj.push_back(Pair("lastrecv", (boost::int64_t)stats.nLastRecv)); + obj.push_back(Pair("bytessent", (boost::int64_t)stats.nSendBytes)); + obj.push_back(Pair("bytesrecv", (boost::int64_t)stats.nRecvBytes)); + obj.push_back(Pair("blocksrequested", (boost::int64_t)stats.nBlocksRequested)); obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected)); obj.push_back(Pair("version", stats.nVersion)); - obj.push_back(Pair("subver", stats.strSubVer)); + // Use the sanitized form of subver here, to avoid tricksy remote peers from + // corrupting or modifiying 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("releasetime", (boost::int64_t)stats.nReleaseTime)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); obj.push_back(Pair("banscore", stats.nMisbehavior)); + if (stats.fSyncNode) + obj.push_back(Pair("syncnode", true)); ret.push_back(obj); } - + + return ret; +} + +Value addnode(const Array& params, bool fHelp) +{ + string strCommand; + if (params.size() == 2) + strCommand = params[1].get_str(); + if (fHelp || params.size() != 2 || + (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) + throw runtime_error( + "addnode \n" + "Attempts add or remove from the addnode list or try a connection to once."); + + string strNode = params[0].get_str(); + + if (strCommand == "onetry") + { + CAddress addr; + ConnectNode(addr, strNode.c_str()); + return Value::null; + } + + LOCK(cs_vAddedNodes); + vector::iterator it = vAddedNodes.begin(); + for(; it != vAddedNodes.end(); it++) + if (strNode == *it) + break; + + if (strCommand == "add") + { + if (it != vAddedNodes.end()) + throw JSONRPCError(-23, "Error: Node already added"); + vAddedNodes.push_back(strNode); + } + else if(strCommand == "remove") + { + if (it == vAddedNodes.end()) + throw JSONRPCError(-24, "Error: Node has not been added."); + vAddedNodes.erase(it); + } + + return Value::null; +} + +Value getaddednodeinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getaddednodeinfo [node]\n" + "Returns information about the given added node, or all added nodes\n" + "(note that onetry addnodes are not listed here)\n" + "If dns is false, only a list of added nodes will be provided,\n" + "otherwise connected information will also be available."); + + bool fDns = params[0].get_bool(); + + list laddedNodes(0); + if (params.size() == 1) + { + LOCK(cs_vAddedNodes); + BOOST_FOREACH(string& strAddNode, vAddedNodes) + laddedNodes.push_back(strAddNode); + } + else + { + string strNode = params[1].get_str(); + LOCK(cs_vAddedNodes); + BOOST_FOREACH(string& strAddNode, vAddedNodes) + if (strAddNode == strNode) + { + laddedNodes.push_back(strAddNode); + break; + } + if (laddedNodes.size() == 0) + throw JSONRPCError(-24, "Error: Node has not been added."); + } + + if (!fDns) + { + Object ret; + BOOST_FOREACH(string& strAddNode, laddedNodes) + ret.push_back(Pair("addednode", strAddNode)); + return ret; + } + + Array ret; + + list > > laddedAddreses(0); + BOOST_FOREACH(string& strAddNode, laddedNodes) + { + vector vservNode(0); + if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) + laddedAddreses.push_back(make_pair(strAddNode, vservNode)); + else + { + Object obj; + obj.push_back(Pair("addednode", strAddNode)); + obj.push_back(Pair("connected", false)); + Array addresses; + obj.push_back(Pair("addresses", addresses)); + } + } + + LOCK(cs_vNodes); + for (list > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) + { + Object obj; + obj.push_back(Pair("addednode", it->first)); + + Array addresses; + bool fConnected = false; + BOOST_FOREACH(CService& addrNode, it->second) + { + bool fFound = false; + Object node; + node.push_back(Pair("address", addrNode.ToString())); + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->addr == addrNode) + { + fFound = true; + fConnected = true; + node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound")); + break; + } + if (!fFound) + node.push_back(Pair("connected", "false")); + addresses.push_back(node); + } + obj.push_back(Pair("connected", fConnected)); + obj.push_back(Pair("addresses", addresses)); + ret.push_back(obj); + } + return ret; } diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 66e4d85..65aa0fe 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -18,15 +18,40 @@ using namespace boost; using namespace boost::assign; using namespace json_spirit; -// These are all in bitcoinrpc.cpp: -extern Object JSONRPCError(int code, const string& message); -extern int64 AmountFromValue(const Value& value); -extern Value ValueFromAmount(int64 amount); -extern std::string HelpRequiringPassphrase(); -extern void EnsureWalletIsUnlocked(); +// +// Utilities: convert hex-encoded Values +// (throws error if not hex). +// +uint256 ParseHashV(const Value& v, string strName) +{ + string strHex; + if (v.type() == str_type) + strHex = v.get_str(); + if (!IsHex(strHex)) // Note: IsHex("") is false + throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + uint256 result; + result.SetHex(strHex); + return result; +} +uint256 ParseHashO(const Object& o, string strKey) +{ + return ParseHashV(find_value(o, strKey), strKey); +} +vector ParseHexV(const Value& v, string strName) +{ + string strHex; + if (v.type() == str_type) + strHex = v.get_str(); + if (!IsHex(strHex)) + throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + return ParseHex(strHex); +} +vector ParseHexO(const Object& o, string strKey) +{ + return ParseHexV(find_value(o, strKey), strKey); +} -void -ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) +void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) { txnouttype type; vector addresses; @@ -50,8 +75,7 @@ ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) out.push_back(Pair("addresses", a)); } -void -TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) { entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("version", tx.nVersion)); @@ -100,6 +124,7 @@ TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) { entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); + entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime)); } else entry.push_back(Pair("confirmations", 0)); @@ -117,8 +142,7 @@ Value getrawtransaction(const Array& params, bool fHelp) "If verbose is non-zero, returns an Object\n" "with information about ."); - uint256 hash; - hash.SetHex(params[0].get_str()); + uint256 hash = ParseHashV(params[0], "parameter 1"); bool fVerbose = false; if (params.size() > 1) @@ -126,8 +150,8 @@ Value getrawtransaction(const Array& params, bool fHelp) CTransaction tx; uint256 hashBlock = 0; - if (!GetTransaction(hash, tx, hashBlock)) - throw JSONRPCError(-5, "No information available about transaction"); + if (!GetTransaction(hash, tx, hashBlock, true)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << tx; @@ -144,38 +168,83 @@ Value getrawtransaction(const Array& params, bool fHelp) Value listunspent(const Array& params, bool fHelp) { - if (fHelp || params.size() > 2) + if (fHelp || params.size() > 3) throw runtime_error( - "listunspent [minconf=1] [maxconf=999999]\n" + "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n" "Returns array of unspent transaction outputs\n" "with between minconf and maxconf (inclusive) confirmations.\n" + "Optionally filtered to only include txouts paid to specified addresses.\n" "Results are an array of Objects, each of which has:\n" "{txid, vout, scriptPubKey, amount, confirmations}"); - RPCTypeCheck(params, list_of(int_type)(int_type)); + RPCTypeCheck(params, list_of(int_type)(int_type)(array_type)); int nMinDepth = 1; if (params.size() > 0) nMinDepth = params[0].get_int(); - int nMaxDepth = 999999; + int nMaxDepth = 9999999; if (params.size() > 1) nMaxDepth = params[1].get_int(); + set setAddress; + if (params.size() > 2) + { + Array inputs = params[2].get_array(); + BOOST_FOREACH(Value& input, inputs) + { + CBitcoinAddress address(input.get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid CasinoCoin address: ")+input.get_str()); + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); + setAddress.insert(address); + } + } + Array results; vector vecOutputs; + assert(pwalletMain != NULL); pwalletMain->AvailableCoins(vecOutputs, false); BOOST_FOREACH(const COutput& out, vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) continue; + if (setAddress.size()) + { + CTxDestination address; + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + continue; + + if (!setAddress.count(address)) + continue; + } + int64 nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; Object entry; entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); entry.push_back(Pair("vout", out.i)); + CTxDestination address; + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + { + entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + if (pwalletMain->mapAddressBook.count(address)) + entry.push_back(Pair("account", pwalletMain->mapAddressBook[address])); + } entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + if (pk.IsPayToScriptHash()) + { + CTxDestination address; + if (ExtractDestination(pk, address)) + { + const CScriptID& hash = boost::get(address); + CScript redeemScript; + if (pwalletMain->GetCScript(hash, redeemScript)) + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } + } entry.push_back(Pair("amount",ValueFromAmount(nValue))); entry.push_back(Pair("confirmations",out.nDepth)); results.push_back(entry); @@ -203,25 +272,20 @@ Value createrawtransaction(const Array& params, bool fHelp) CTransaction rawTx; - BOOST_FOREACH(Value& input, inputs) + BOOST_FOREACH(const Value& input, inputs) { const Object& o = input.get_obj(); - const Value& txid_v = find_value(o, "txid"); - if (txid_v.type() != str_type) - throw JSONRPCError(-8, "Invalid parameter, missing txid key"); - string txid = txid_v.get_str(); - if (!IsHex(txid)) - throw JSONRPCError(-8, "Invalid parameter, expected hex txid"); + uint256 txid = ParseHashO(o, "txid"); const Value& vout_v = find_value(o, "vout"); if (vout_v.type() != int_type) - throw JSONRPCError(-8, "Invalid parameter, missing vout key"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); int nOutput = vout_v.get_int(); if (nOutput < 0) - throw JSONRPCError(-8, "Invalid parameter, vout must be positive"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - CTxIn in(COutPoint(uint256(txid), nOutput)); + CTxIn in(COutPoint(txid, nOutput)); rawTx.vin.push_back(in); } @@ -230,10 +294,10 @@ Value createrawtransaction(const Array& params, bool fHelp) { CBitcoinAddress address(s.name_); if (!address.IsValid()) - throw JSONRPCError(-5, string("Invalid Bitcoin address:")+s.name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid CasinoCoin address: ")+s.name_); if (setAddress.count(address)) - throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); setAddress.insert(address); CScript scriptPubKey; @@ -256,16 +320,14 @@ Value decoderawtransaction(const Array& params, bool fHelp) "decoderawtransaction \n" "Return a JSON object representing the serialized, hex-encoded transaction."); - RPCTypeCheck(params, list_of(str_type)); - - vector txData(ParseHex(params[0].get_str())); + vector txData(ParseHexV(params[0], "argument")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; try { ssData >> tx; } catch (std::exception &e) { - throw JSONRPCError(-22, "TX decode failed"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); } Object result; @@ -278,25 +340,22 @@ Value signrawtransaction(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) throw runtime_error( - "signrawtransaction [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [,...] [sighashtype=\"ALL\"]\n" + "signrawtransaction [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [,...] [sighashtype=\"ALL\"]\n" "Sign inputs for raw transaction (serialized, hex-encoded).\n" - "Second optional argument is an array of previous transaction outputs that\n" - "this transaction depends on but may not yet be in the blockchain.\n" - "Third optional argument is an array of base58-encoded private\n" + "Second optional argument (may be null) is an array of previous transaction outputs that\n" + "this transaction depends on but may not yet be in the block chain.\n" + "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" - "Fourth option is a string that is one of six values; ALL, NONE, SINGLE or\n" + "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n" "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n" "Returns json object with keys:\n" " hex : raw transaction with signature(s) (hex-encoded string)\n" " complete : 1 if transaction has a complete set of signature (0 if not)" + HelpRequiringPassphrase()); - if (params.size() < 3) - EnsureWalletIsUnlocked(); + RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); - RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)); - - vector txData(ParseHex(params[0].get_str())); + vector txData(ParseHexV(params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); vector txVariants; while (!ssData.empty()) @@ -307,12 +366,12 @@ Value signrawtransaction(const Array& params, bool fHelp) txVariants.push_back(tx); } catch (std::exception &e) { - throw JSONRPCError(-22, "TX decode failed"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); } } if (txVariants.empty()) - throw JSONRPCError(-22, "Missing transaction"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction"); // mergedTx will end up with all the signatures; it // starts as a clone of the rawtx: @@ -320,72 +379,26 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fComplete = true; // Fetch previous transactions (inputs): - map mapPrevOut; + CCoinsView viewDummy; + CCoinsViewCache view(viewDummy); { - MapPrevTx mapPrevTx; - CTxDB txdb("r"); - map unused; - bool fInvalid; - mergedTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid); + LOCK(mempool.cs); + CCoinsViewCache &viewChain = *pcoinsTip; + CCoinsViewMemPool viewMempool(viewChain, mempool); + view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - // Copy results into mapPrevOut: - BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) - { + BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { const uint256& prevHash = txin.prevout.hash; - if (mapPrevTx.count(prevHash)) - mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey; + CCoins coins; + view.GetCoins(prevHash, coins); // this is certainly allowed to fail } - } - // Add previous txouts given in the RPC call: - if (params.size() > 1) - { - Array prevTxs = params[1].get_array(); - BOOST_FOREACH(Value& p, prevTxs) - { - if (p.type() != obj_type) - throw JSONRPCError(-22, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); - - Object prevOut = p.get_obj(); - - RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); - - string txidHex = find_value(prevOut, "txid").get_str(); - if (!IsHex(txidHex)) - throw JSONRPCError(-22, "txid must be hexadecimal"); - uint256 txid; - txid.SetHex(txidHex); - - int nOut = find_value(prevOut, "vout").get_int(); - if (nOut < 0) - throw JSONRPCError(-22, "vout must be positive"); - - string pkHex = find_value(prevOut, "scriptPubKey").get_str(); - if (!IsHex(pkHex)) - throw JSONRPCError(-22, "scriptPubKey must be hexadecimal"); - vector pkData(ParseHex(pkHex)); - CScript scriptPubKey(pkData.begin(), pkData.end()); - - COutPoint outpoint(txid, nOut); - if (mapPrevOut.count(outpoint)) - { - // Complain if scriptPubKey doesn't match - if (mapPrevOut[outpoint] != scriptPubKey) - { - string err("Previous output scriptPubKey mismatch:\n"); - err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+ - scriptPubKey.ToString(); - throw JSONRPCError(-22, err); - } - } - else - mapPrevOut[outpoint] = scriptPubKey; - } + view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long } bool fGivenKeys = false; CBasicKeyStore tempKeystore; - if (params.size() > 2) + if (params.size() > 2 && params[2].type() != null_type) { fGivenKeys = true; Array keys = params[2].get_array(); @@ -394,18 +407,72 @@ Value signrawtransaction(const Array& params, bool fHelp) CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(k.get_str()); if (!fGood) - throw JSONRPCError(-5,"Invalid private key"); - CKey key; - bool fCompressed; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); + CKey key = vchSecret.GetKey(); tempKeystore.AddKey(key); } } - const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); + else + EnsureWalletIsUnlocked(); + + // Add previous txouts given in the RPC call: + if (params.size() > 1 && params[1].type() != null_type) + { + Array prevTxs = params[1].get_array(); + BOOST_FOREACH(Value& p, prevTxs) + { + if (p.type() != obj_type) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); + + Object prevOut = p.get_obj(); + + RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); + + uint256 txid = ParseHashO(prevOut, "txid"); + + int nOut = find_value(prevOut, "vout").get_int(); + if (nOut < 0) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); + + vector pkData(ParseHexO(prevOut, "scriptPubKey")); + CScript scriptPubKey(pkData.begin(), pkData.end()); + + CCoins coins; + if (view.GetCoins(txid, coins)) { + if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { + string err("Previous output scriptPubKey mismatch:\n"); + err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ + scriptPubKey.ToString(); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); + } + // what todo if txid is known, but the actual output isn't? + } + if ((unsigned int)nOut >= coins.vout.size()) + coins.vout.resize(nOut+1); + coins.vout[nOut].scriptPubKey = scriptPubKey; + coins.vout[nOut].nValue = 0; // we don't know the actual output value + view.SetCoins(txid, coins); + + // if redeemScript given and not using the local wallet (private keys + // given), add redeemScript to the tempKeystore so it can be signed: + if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) + { + RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type)); + Value v = find_value(prevOut, "redeemScript"); + if (!(v == Value::null)) + { + vector rsData(ParseHexV(v, "redeemScript")); + CScript redeemScript(rsData.begin(), rsData.end()); + tempKeystore.AddCScript(redeemScript); + } + } + } + } + + const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); int nHashType = SIGHASH_ALL; - if (params.size() > 3) + if (params.size() > 3 && params[3].type() != null_type) { static map mapSigHashValues = boost::assign::map_list_of @@ -420,29 +487,34 @@ Value signrawtransaction(const Array& params, bool fHelp) if (mapSigHashValues.count(strHashType)) nHashType = mapSigHashValues[strHashType]; else - throw JSONRPCError(-8, "Invalid sighash param"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); } + bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; - if (mapPrevOut.count(txin.prevout) == 0) + CCoins coins; + if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) { fComplete = false; continue; } - const CScript& prevPubKey = mapPrevOut[txin.prevout]; + const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey; txin.scriptSig.clear(); - SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + // Only sign SIGHASH_SINGLE if there's a corresponding output: + if (!fHashSingle || (i < mergedTx.vout.size())) + SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); // ... and merge in other signatures: BOOST_FOREACH(const CTransaction& txv, txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0)) + if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)) fComplete = false; } @@ -462,10 +534,8 @@ Value sendrawtransaction(const Array& params, bool fHelp) "sendrawtransaction \n" "Submits raw transaction (serialized, hex-encoded) to local node and network."); - RPCTypeCheck(params, list_of(str_type)); - // parse hex string from parameter - vector txData(ParseHex(params[0].get_str())); + vector txData(ParseHexV(params[0], "parameter")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; @@ -474,31 +544,31 @@ Value sendrawtransaction(const Array& params, bool fHelp) ssData >> tx; } catch (std::exception &e) { - throw JSONRPCError(-22, "TX decode failed"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); } uint256 hashTx = tx.GetHash(); - // See if the transaction is already in a block - // or in the memory pool: - CTransaction existingTx; - uint256 hashBlock = 0; - if (GetTransaction(hashTx, existingTx, hashBlock)) + bool fHave = false; + CCoinsViewCache &view = *pcoinsTip; + CCoins existingCoins; { - if (hashBlock != 0) - throw JSONRPCError(-5, string("transaction already in block ")+hashBlock.GetHex()); + fHave = view.GetCoins(hashTx, existingCoins); + if (!fHave) { + // push to local node + CValidationState state; + if (!tx.AcceptToMemoryPool(state, true, false)) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state + } + } + if (fHave) { + if (existingCoins.nHeight < 1000000000) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain"); // Not in block, but already in the memory pool; will drop // through to re-relay it. + } else { + SyncWithWallets(hashTx, tx, NULL, true); } - else - { - // push to local node - CTxDB txdb("r"); - if (!tx.AcceptToMemoryPool(txdb)) - throw JSONRPCError(-22, "TX rejected"); - - SyncWithWallets(tx, NULL, true); - } - RelayMessage(CInv(MSG_TX, hashTx), tx); + RelayTransaction(tx, hashTx); return hashTx.GetHex(); } diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp new file mode 100644 index 0000000..b184ae7 --- /dev/null +++ b/src/rpcwallet.cpp @@ -0,0 +1,1609 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include "wallet.h" +#include "walletdb.h" +#include "bitcoinrpc.h" +#include "init.h" +#include "base58.h" + +using namespace std; +using namespace boost; +using namespace boost::assign; +using namespace json_spirit; + +int64 nWalletUnlockTime; +static CCriticalSection cs_nWalletUnlockTime; + +std::string HelpRequiringPassphrase() +{ + return pwalletMain && pwalletMain->IsCrypted() + ? "\nrequires wallet passphrase to be set with walletpassphrase first" + : ""; +} + +void EnsureWalletIsUnlocked() +{ + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); +} + +void WalletTxToJSON(const CWalletTx& wtx, Object& entry) +{ + int confirms = wtx.GetDepthInMainChain(); + entry.push_back(Pair("confirmations", confirms)); + if (wtx.IsCoinBase()) + entry.push_back(Pair("generated", true)); + if (confirms) + { + entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); + entry.push_back(Pair("blockindex", wtx.nIndex)); + entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime))); + } + entry.push_back(Pair("txid", wtx.GetHash().GetHex())); + entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); + entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived)); + BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) + entry.push_back(Pair(item.first, item.second)); +} + +string AccountFromValue(const Value& value) +{ + string strAccount = value.get_str(); + if (strAccount == "*") + throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); + return strAccount; +} + +Value getinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getinfo\n" + "Returns an object containing various state info."); + + proxyType proxy; + GetProxy(NET_IPV4, proxy); + + Object obj; + obj.push_back(Pair("version", (int)CLIENT_VERSION)); + obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); + if (pwalletMain) { + obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + } + obj.push_back(Pair("blocks", (int)nBestHeight)); + obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset())); + obj.push_back(Pair("connections", (int)vNodes.size())); + obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("testnet", fTestNet)); + if (pwalletMain) { + obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); + } + obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue))); + if (pwalletMain && pwalletMain->IsCrypted()) + obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + return obj; +} + + + +Value getnewaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnewaddress [account]\n" + "Returns a new CasinoCoin address for receiving payments. " + "If [account] is specified (recommended), it is added to the address book " + "so payments received with the address will be credited to [account]."); + + // 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]); + + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + // Generate a new key that is added to wallet + CPubKey newKey; + if (!pwalletMain->GetKeyFromPool(newKey, false)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + CKeyID keyID = newKey.GetID(); + + pwalletMain->SetAddressBookName(keyID, strAccount); + + return CBitcoinAddress(keyID).ToString(); +} + + +CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + + CAccount account; + walletdb.ReadAccount(strAccount, account); + + bool bKeyUsed = false; + + // Check if the current key has been used + if (account.vchPubKey.IsValid()) + { + CScript scriptPubKey; + scriptPubKey.SetDestination(account.vchPubKey.GetID()); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); + ++it) + { + const CWalletTx& wtx = (*it).second; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + bKeyUsed = true; + } + } + + // Generate a new key + if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) + { + if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount); + walletdb.WriteAccount(strAccount, account); + } + + return CBitcoinAddress(account.vchPubKey.GetID()); +} + +Value getaccountaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaccountaddress \n" + "Returns the current CasinoCoin address for receiving payments to this account."); + + // Parse the account first so we don't generate a key if there's an error + string strAccount = AccountFromValue(params[0]); + + Value ret; + + ret = GetAccountAddress(strAccount).ToString(); + + return ret; +} + + + +Value setaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setaccount \n" + "Sets the account associated with the given address."); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid CasinoCoin address"); + + + string strAccount; + if (params.size() > 1) + strAccount = AccountFromValue(params[1]); + + // 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()]; + if (address == GetAccountAddress(strOldAccount)) + GetAccountAddress(strOldAccount, true); + } + + pwalletMain->SetAddressBookName(address.Get(), strAccount); + + return Value::null; +} + + +Value getaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaccount \n" + "Returns the account associated with the given address."); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid CasinoCoin address"); + + string strAccount; + map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); + if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) + strAccount = (*mi).second; + return strAccount; +} + + +Value getaddressesbyaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddressesbyaccount \n" + "Returns the list of addresses for the given account."); + + string strAccount = AccountFromValue(params[0]); + + // Find all addresses that have the given account + Array ret; + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) + { + const CBitcoinAddress& address = item.first; + const string& strName = item.second; + if (strName == strAccount) + ret.push_back(address.ToString()); + } + return ret; +} + + +Value setmininput(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "setmininput \n" + " is a real and is rounded to the nearest 0.00000001"); + + // Amount + int64 nAmount = 0; + if (params[0].get_real() != 0.0) + nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts + + nMinimumInputValue = nAmount; + return true; +} + + +Value sendtoaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "sendtoaddress [comment] [comment-to]\n" + " is a real and is rounded to the nearest 0.00000001" + + HelpRequiringPassphrase()); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid CasinoCoin address"); + + // Amount + int64 nAmount = AmountFromValue(params[1]); + + // Wallet comments + CWalletTx wtx; + if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) + wtx.mapValue["comment"] = params[2].get_str(); + if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + wtx.mapValue["to"] = params[3].get_str(); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); + if (strError != "") + throw JSONRPCError(RPC_WALLET_ERROR, strError); + + return wtx.GetHash().GetHex(); +} + +Value listaddressgroupings(const Array& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "listaddressgroupings\n" + "Lists groups of addresses which have had their common ownership\n" + "made public by common use as inputs or as the resulting change\n" + "in past transactions"); + + Array jsonGroupings; + map balances = pwalletMain->GetAddressBalances(); + BOOST_FOREACH(set grouping, pwalletMain->GetAddressGroupings()) + { + Array jsonGrouping; + BOOST_FOREACH(CTxDestination address, grouping) + { + Array addressInfo; + addressInfo.push_back(CBitcoinAddress(address).ToString()); + addressInfo.push_back(ValueFromAmount(balances[address])); + { + LOCK(pwalletMain->cs_wallet); + if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) + addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second); + } + jsonGrouping.push_back(addressInfo); + } + jsonGroupings.push_back(jsonGrouping); + } + return jsonGroupings; +} + +Value signmessage(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "signmessage \n" + "Sign a message with the private key of an address"); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + string strMessage = params[1].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + + CKey key; + if (!pwalletMain->GetKey(keyID, key)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); + + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; + + vector vchSig; + if (!key.SignCompact(ss.GetHash(), vchSig)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); + + return EncodeBase64(&vchSig[0], vchSig.size()); +} + +Value verifymessage(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "verifymessage \n" + "Verify a signed message"); + + string strAddress = params[0].get_str(); + string strSign = params[1].get_str(); + string strMessage = params[2].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + + bool fInvalid = false; + vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); + + if (fInvalid) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); + + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; + + CPubKey pubkey; + if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) + return false; + + return (pubkey.GetID() == keyID); +} + + +Value getreceivedbyaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getreceivedbyaddress [minconf=1]\n" + "Returns the total amount received by in transactions with at least [minconf] confirmations."); + + // Bitcoin address + CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); + CScript scriptPubKey; + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid CasinoCoin address"); + scriptPubKey.SetDestination(address.Get()); + if (!IsMine(*pwalletMain,scriptPubKey)) + return (double)0.0; + + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + // Tally + int64 nAmount = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (wtx.IsCoinBase() || !wtx.IsFinal()) + continue; + + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + if (wtx.GetDepthInMainChain() >= nMinDepth) + nAmount += txout.nValue; + } + + return ValueFromAmount(nAmount); +} + + +void GetAccountAddresses(string strAccount, set& setAddress) +{ + BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook) + { + const CTxDestination& address = item.first; + const string& strName = item.second; + if (strName == strAccount) + setAddress.insert(address); + } +} + +Value getreceivedbyaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getreceivedbyaccount [minconf=1]\n" + "Returns the total amount received by addresses with in transactions with at least [minconf] confirmations."); + + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + // Get the set of pub keys assigned to account + string strAccount = AccountFromValue(params[0]); + set setAddress; + GetAccountAddresses(strAccount, setAddress); + + // Tally + int64 nAmount = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (wtx.IsCoinBase() || !wtx.IsFinal()) + continue; + + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) + if (wtx.GetDepthInMainChain() >= nMinDepth) + nAmount += txout.nValue; + } + } + + return (double)nAmount / (double)COIN; +} + + +int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) +{ + int64 nBalance = 0; + + // Tally wallet transactions + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (!wtx.IsFinal()) + continue; + + int64 nReceived, nSent, nFee; + wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee); + + if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) + nBalance += nReceived; + nBalance -= nSent + nFee; + } + + // Tally internal accounting entries + nBalance += walletdb.GetAccountCreditDebit(strAccount); + + return nBalance; +} + +int64 GetAccountBalance(const string& strAccount, int nMinDepth) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + return GetAccountBalance(walletdb, strAccount, nMinDepth); +} + + +Value getbalance(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getbalance [account] [minconf=1]\n" + "If [account] is not specified, returns the server's total available balance.\n" + "If [account] is specified, returns the balance in the account."); + + if (params.size() == 0) + return ValueFromAmount(pwalletMain->GetBalance()); + + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + if (params[0].get_str() == "*") { + // Calculate total balance a different way from GetBalance() + // (GetBalance() sums up all unspent TxOuts) + // getbalance and getbalance '*' 0 should return the same number + int64 nBalance = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (!wtx.IsConfirmed()) + continue; + + int64 allFee; + string strSentAccount; + list > listReceived; + list > listSent; + wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount); + if (wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived) + nBalance += r.second; + } + BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent) + nBalance -= r.second; + nBalance -= allFee; + } + return ValueFromAmount(nBalance); + } + + string strAccount = AccountFromValue(params[0]); + + int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + + return ValueFromAmount(nBalance); +} + + +Value movecmd(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 5) + throw runtime_error( + "move [minconf=1] [comment]\n" + "Move from one account in your wallet to another."); + + string strFrom = AccountFromValue(params[0]); + string strTo = AccountFromValue(params[1]); + int64 nAmount = AmountFromValue(params[2]); + if (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(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + if (!walletdb.TxnBegin()) + throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + + int64 nNow = GetAdjustedTime(); + + // Debit + CAccountingEntry debit; + debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); + debit.strAccount = strFrom; + debit.nCreditDebit = -nAmount; + debit.nTime = nNow; + debit.strOtherAccount = strTo; + debit.strComment = strComment; + walletdb.WriteAccountingEntry(debit); + + // Credit + CAccountingEntry credit; + credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); + credit.strAccount = strTo; + credit.nCreditDebit = nAmount; + credit.nTime = nNow; + credit.strOtherAccount = strFrom; + credit.strComment = strComment; + walletdb.WriteAccountingEntry(credit); + + if (!walletdb.TxnCommit()) + throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + + return true; +} + + +Value sendfrom(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 6) + throw runtime_error( + "sendfrom [minconf=1] [comment] [comment-to]\n" + " is a real and is rounded to the nearest 0.00000001" + + HelpRequiringPassphrase()); + + string strAccount = AccountFromValue(params[0]); + CBitcoinAddress address(params[1].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid CasinoCoin address"); + int64 nAmount = AmountFromValue(params[2]); + int nMinDepth = 1; + if (params.size() > 3) + nMinDepth = params[3].get_int(); + + CWalletTx wtx; + wtx.strFromAccount = strAccount; + if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty()) + wtx.mapValue["comment"] = params[4].get_str(); + if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty()) + wtx.mapValue["to"] = params[5].get_str(); + + EnsureWalletIsUnlocked(); + + // Check funds + int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + if (nAmount > nBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + + // Send + string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); + if (strError != "") + throw JSONRPCError(RPC_WALLET_ERROR, strError); + + return wtx.GetHash().GetHex(); +} + + +Value sendmany(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "sendmany {address:amount,...} [minconf=1] [comment]\n" + "amounts are double-precision floating point numbers" + + HelpRequiringPassphrase()); + + string strAccount = AccountFromValue(params[0]); + Object sendTo = params[1].get_obj(); + int nMinDepth = 1; + if (params.size() > 2) + nMinDepth = params[2].get_int(); + + CWalletTx wtx; + wtx.strFromAccount = strAccount; + if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + wtx.mapValue["comment"] = params[3].get_str(); + + set setAddress; + vector > vecSend; + + int64 totalAmount = 0; + BOOST_FOREACH(const Pair& s, sendTo) + { + CBitcoinAddress address(s.name_); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid CasinoCoin address: ")+s.name_); + + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); + setAddress.insert(address); + + CScript scriptPubKey; + scriptPubKey.SetDestination(address.Get()); + int64 nAmount = AmountFromValue(s.value_); + totalAmount += nAmount; + + vecSend.push_back(make_pair(scriptPubKey, nAmount)); + } + + EnsureWalletIsUnlocked(); + + // Check funds + int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + if (totalAmount > nBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + + // Send + CReserveKey keyChange(pwalletMain); + int64 nFeeRequired = 0; + string strFailReason; + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); + if (!fCreated) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); + if (!pwalletMain->CommitTransaction(wtx, keyChange)) + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + return wtx.GetHash().GetHex(); +} + +// +// Used by addmultisigaddress / createmultisig: +// +static CScript _createmultisig(const Array& params) +{ + int nRequired = params[0].get_int(); + const Array& 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"); + if ((int)keys.size() < nRequired) + throw runtime_error( + strprintf("not enough keys supplied " + "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); + std::vector pubkeys; + pubkeys.resize(keys.size()); + for (unsigned int i = 0; i < keys.size(); i++) + { + const std::string& ks = keys[i].get_str(); + + // Case 1: CasinoCoin address and we have full public key: + CBitcoinAddress address(ks); + if (pwalletMain && address.IsValid()) + { + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw runtime_error( + strprintf("%s does not refer to a key",ks.c_str())); + CPubKey vchPubKey; + if (!pwalletMain->GetPubKey(keyID, vchPubKey)) + throw runtime_error( + strprintf("no full public key for address %s",ks.c_str())); + if (!vchPubKey.IsFullyValid()) + throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; + } + + // Case 2: hex public key + else if (IsHex(ks)) + { + CPubKey vchPubKey(ParseHex(ks)); + if (!vchPubKey.IsFullyValid()) + throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; + } + else + { + throw runtime_error(" Invalid public key: "+ks); + } + } + CScript result; + result.SetMultisig(nRequired, pubkeys); + return result; +} + +Value addmultisigaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + { + string msg = "addmultisigaddress <'[\"key\",\"key\"]'> [account]\n" + "Add a nrequired-to-sign multisignature address to the wallet\"\n" + "each key is a CasinoCoin address or hex-encoded public key\n" + "If [account] is specified, assign address to [account]."; + throw runtime_error(msg); + } + + string strAccount; + if (params.size() > 2) + strAccount = AccountFromValue(params[2]); + + // Construct using pay-to-script-hash: + CScript inner = _createmultisig(params); + CScriptID innerID = inner.GetID(); + pwalletMain->AddCScript(inner); + + pwalletMain->SetAddressBookName(innerID, strAccount); + return CBitcoinAddress(innerID).ToString(); +} + +Value createmultisig(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 2) + { + string msg = "createmultisig <'[\"key\",\"key\"]'>\n" + "Creates a multi-signature address and returns a json object\n" + "with keys:\n" + "address : casinocoin address\n" + "redeemScript : hex-encoded redemption script"; + throw runtime_error(msg); + } + + // Construct using pay-to-script-hash: + CScript inner = _createmultisig(params); + CScriptID innerID = inner.GetID(); + CBitcoinAddress address(innerID); + + Object result; + result.push_back(Pair("address", address.ToString())); + result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); + + return result; +} + + +struct tallyitem +{ + int64 nAmount; + int nConf; + vector txids; + tallyitem() + { + nAmount = 0; + nConf = std::numeric_limits::max(); + } +}; + +Value ListReceived(const Array& params, bool fByAccounts) +{ + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + // Whether to include empty accounts + bool fIncludeEmpty = false; + if (params.size() > 1) + fIncludeEmpty = params[1].get_bool(); + + // Tally + map mapTally; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + + if (wtx.IsCoinBase() || !wtx.IsFinal()) + continue; + + int nDepth = wtx.GetDepthInMainChain(); + if (nDepth < nMinDepth) + continue; + + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + CTxDestination address; + if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address)) + continue; + + tallyitem& item = mapTally[address]; + item.nAmount += txout.nValue; + item.nConf = min(item.nConf, nDepth); + item.txids.push_back(wtx.GetHash()); + } + } + + // Reply + Array ret; + map mapAccountTally; + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) + { + const CBitcoinAddress& address = item.first; + const string& strAccount = item.second; + map::iterator it = mapTally.find(address); + if (it == mapTally.end() && !fIncludeEmpty) + continue; + + int64 nAmount = 0; + int nConf = std::numeric_limits::max(); + if (it != mapTally.end()) + { + nAmount = (*it).second.nAmount; + nConf = (*it).second.nConf; + } + + if (fByAccounts) + { + tallyitem& item = mapAccountTally[strAccount]; + item.nAmount += nAmount; + item.nConf = min(item.nConf, nConf); + } + else + { + Object obj; + obj.push_back(Pair("address", address.ToString())); + obj.push_back(Pair("account", strAccount)); + obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + Array transactions; + if (it != mapTally.end()) + { + BOOST_FOREACH(const uint256& item, (*it).second.txids) + { + transactions.push_back(item.GetHex()); + } + } + obj.push_back(Pair("txids", transactions)); + ret.push_back(obj); + } + } + + if (fByAccounts) + { + for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) + { + int64 nAmount = (*it).second.nAmount; + int nConf = (*it).second.nConf; + Object obj; + obj.push_back(Pair("account", (*it).first)); + obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + ret.push_back(obj); + } + } + + return ret; +} + +Value listreceivedbyaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "listreceivedbyaddress [minconf=1] [includeempty=false]\n" + "[minconf] is the minimum number of confirmations before payments are included.\n" + "[includeempty] whether to include addresses that haven't received any payments.\n" + "Returns an array of objects containing:\n" + " \"address\" : receiving address\n" + " \"account\" : the account of the receiving address\n" + " \"amount\" : total amount received by the address\n" + " \"confirmations\" : number of confirmations of the most recent transaction included\n" + " \"txids\" : list of transactions with outputs to the address\n"); + + return ListReceived(params, false); +} + +Value listreceivedbyaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "listreceivedbyaccount [minconf=1] [includeempty=false]\n" + "[minconf] is the minimum number of confirmations before payments are included.\n" + "[includeempty] whether to include accounts that haven't received any payments.\n" + "Returns an array of objects containing:\n" + " \"account\" : the account of the receiving addresses\n" + " \"amount\" : total amount received by addresses with this account\n" + " \"confirmations\" : number of confirmations of the most recent transaction included"); + + return ListReceived(params, true); +} + +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret) +{ + int64 nFee; + string strSentAccount; + list > listReceived; + list > listSent; + + wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount); + + bool fAllAccounts = (strAccount == string("*")); + + // Sent + if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + { + Object entry; + entry.push_back(Pair("account", strSentAccount)); + entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString())); + entry.push_back(Pair("category", "send")); + entry.push_back(Pair("amount", ValueFromAmount(-s.second))); + entry.push_back(Pair("fee", ValueFromAmount(-nFee))); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + } + + // Received + if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + { + string account; + if (pwalletMain->mapAddressBook.count(r.first)) + account = pwalletMain->mapAddressBook[r.first]; + if (fAllAccounts || (account == strAccount)) + { + Object entry; + entry.push_back(Pair("account", account)); + entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString())); + if (wtx.IsCoinBase()) + { + if (wtx.GetDepthInMainChain() < 1) + entry.push_back(Pair("category", "orphan")); + else if (wtx.GetBlocksToMaturity() > 0) + entry.push_back(Pair("category", "immature")); + else + entry.push_back(Pair("category", "generate")); + } + else + entry.push_back(Pair("category", "receive")); + entry.push_back(Pair("amount", ValueFromAmount(r.second))); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + } + } +} + +void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret) +{ + bool fAllAccounts = (strAccount == string("*")); + + if (fAllAccounts || acentry.strAccount == strAccount) + { + Object entry; + entry.push_back(Pair("account", acentry.strAccount)); + entry.push_back(Pair("category", "move")); + entry.push_back(Pair("time", (boost::int64_t)acentry.nTime)); + entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); + entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); + entry.push_back(Pair("comment", acentry.strComment)); + ret.push_back(entry); + } +} + +Value listtransactions(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "listtransactions [account] [count=10] [from=0]\n" + "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account]."); + + string strAccount = "*"; + if (params.size() > 0) + strAccount = params[0].get_str(); + int nCount = 10; + if (params.size() > 1) + nCount = params[1].get_int(); + int nFrom = 0; + if (params.size() > 2) + nFrom = params[2].get_int(); + + if (nCount < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); + if (nFrom < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); + + Array ret; + + std::list acentries; + CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + + // iterate backwards until we have nCount items to return: + for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + { + CWalletTx *const pwtx = (*it).second.first; + if (pwtx != 0) + ListTransactions(*pwtx, strAccount, 0, true, ret); + CAccountingEntry *const pacentry = (*it).second.second; + if (pacentry != 0) + AcentryToJSON(*pacentry, strAccount, ret); + + if ((int)ret.size() >= (nCount+nFrom)) break; + } + // ret is newest to oldest + + if (nFrom > (int)ret.size()) + nFrom = ret.size(); + if ((nFrom + nCount) > (int)ret.size()) + nCount = ret.size() - nFrom; + Array::iterator first = ret.begin(); + std::advance(first, nFrom); + Array::iterator last = ret.begin(); + std::advance(last, nFrom+nCount); + + if (last != ret.end()) ret.erase(last, ret.end()); + if (first != ret.begin()) ret.erase(ret.begin(), first); + + std::reverse(ret.begin(), ret.end()); // Return oldest to newest + + return ret; +} + +Value listaccounts(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "listaccounts [minconf=1]\n" + "Returns Object that has account names as keys, account balances as values."); + + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + map mapAccountBalances; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { + if (IsMine(*pwalletMain, entry.first)) // This address belongs to me + mapAccountBalances[entry.second] = 0; + } + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + int64 nFee; + string strSentAccount; + list > listReceived; + list > listSent; + wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount); + mapAccountBalances[strSentAccount] -= nFee; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + mapAccountBalances[strSentAccount] -= s.second; + if (wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + if (pwalletMain->mapAddressBook.count(r.first)) + mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; + else + mapAccountBalances[""] += r.second; + } + } + + list acentries; + CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); + BOOST_FOREACH(const CAccountingEntry& entry, acentries) + mapAccountBalances[entry.strAccount] += entry.nCreditDebit; + + Object ret; + BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) { + ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); + } + return ret; +} + +Value listsinceblock(const Array& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "listsinceblock [blockhash] [target-confirmations]\n" + "Get all transactions in blocks since block [blockhash], or all transactions if omitted"); + + CBlockIndex *pindex = NULL; + int target_confirms = 1; + + if (params.size() > 0) + { + uint256 blockId = 0; + + blockId.SetHex(params[0].get_str()); + pindex = CBlockLocator(blockId).GetBlockIndex(); + } + + if (params.size() > 1) + { + target_confirms = params[1].get_int(); + + if (target_confirms < 1) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); + } + + int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; + + Array transactions; + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) + { + CWalletTx tx = (*it).second; + + if (depth == -1 || tx.GetDepthInMainChain() < depth) + ListTransactions(tx, "*", 0, true, transactions); + } + + uint256 lastblock; + + if (target_confirms == 1) + { + lastblock = hashBestChain; + } + else + { + int target_height = pindexBest->nHeight + 1 - target_confirms; + + CBlockIndex *block; + for (block = pindexBest; + block && block->nHeight > target_height; + block = block->pprev) { } + + lastblock = block ? block->GetBlockHash() : 0; + } + + Object ret; + ret.push_back(Pair("transactions", transactions)); + ret.push_back(Pair("lastblock", lastblock.GetHex())); + + return ret; +} + +Value gettransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "gettransaction \n" + "Get detailed information about in-wallet transaction "); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + Object entry; + if (!pwalletMain->mapWallet.count(hash)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); + + entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); + if (wtx.IsFromMe()) + entry.push_back(Pair("fee", ValueFromAmount(nFee))); + + WalletTxToJSON(wtx, entry); + + Array details; + ListTransactions(wtx, "*", 0, false, details); + entry.push_back(Pair("details", details)); + + return entry; +} + + +Value backupwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "backupwallet \n" + "Safely copies wallet.dat to destination, which can be a directory or a path with filename."); + + string strDest = params[0].get_str(); + if (!BackupWallet(*pwalletMain, strDest)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); + + return Value::null; +} + + +Value keypoolrefill(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "keypoolrefill\n" + "Fills the keypool." + + HelpRequiringPassphrase()); + + EnsureWalletIsUnlocked(); + + pwalletMain->TopUpKeyPool(); + + if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); + + return Value::null; +} + + +void ThreadTopUpKeyPool(void* parg) +{ + // Make this thread recognisable as the key-topping-up thread + RenameThread("bitcoin-key-top"); + + pwalletMain->TopUpKeyPool(); +} + +void ThreadCleanWalletPassphrase(void* parg) +{ + // Make this thread recognisable as the wallet relocking thread + RenameThread("bitcoin-lock-wa"); + + int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000; + + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); + + if (nWalletUnlockTime == 0) + { + nWalletUnlockTime = nMyWakeTime; + + do + { + if (nWalletUnlockTime==0) + break; + int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); + if (nToSleep <= 0) + break; + + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); + MilliSleep(nToSleep); + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); + + } while(1); + + if (nWalletUnlockTime) + { + nWalletUnlockTime = 0; + pwalletMain->Lock(); + } + } + else + { + if (nWalletUnlockTime < nMyWakeTime) + nWalletUnlockTime = nMyWakeTime; + } + + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); + + delete (int64*)parg; +} + +Value walletpassphrase(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) + throw runtime_error( + "walletpassphrase \n" + "Stores the wallet decryption key in memory for seconds."); + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); + + if (!pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked."); + + // Note that the walletpassphrase is stored in 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(); + + if (strWalletPass.length() > 0) + { + if (!pwalletMain->Unlock(strWalletPass)) + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + } + else + throw runtime_error( + "walletpassphrase \n" + "Stores the wallet decryption key in memory for seconds."); + + NewThread(ThreadTopUpKeyPool, NULL); + int64* pnSleepTime = new int64(params[1].get_int64()); + NewThread(ThreadCleanWalletPassphrase, pnSleepTime); + + return Value::null; +} + + +Value walletpassphrasechange(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + if (fHelp) + return true; + if (!pwalletMain->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. + SecureString strOldWalletPass; + strOldWalletPass.reserve(100); + strOldWalletPass = params[0].get_str().c_str(); + + SecureString strNewWalletPass; + strNewWalletPass.reserve(100); + strNewWalletPass = params[1].get_str().c_str(); + + if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + + if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + + return Value::null; +} + + +Value walletlock(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) + throw runtime_error( + "walletlock\n" + "Removes the wallet encryption key from memory, locking the wallet.\n" + "After calling this method, you will need to call walletpassphrase again\n" + "before being able to call any methods which require the wallet to be unlocked."); + if (fHelp) + return true; + if (!pwalletMain->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; + } + + return Value::null; +} + + +Value encryptwallet(const Array& params, bool fHelp) +{ + if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + if (fHelp) + return true; + if (pwalletMain->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. + SecureString strWalletPass; + strWalletPass.reserve(100); + strWalletPass = params[0].get_str().c_str(); + + if (strWalletPass.length() < 1) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + + if (!pwalletMain->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; CasinoCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; +} + +class DescribeAddressVisitor : public boost::static_visitor +{ +public: + Object operator()(const CNoDestination &dest) const { return Object(); } + + Object operator()(const CKeyID &keyID) const { + Object obj; + CPubKey vchPubKey; + pwalletMain->GetPubKey(keyID, vchPubKey); + obj.push_back(Pair("isscript", false)); + obj.push_back(Pair("pubkey", HexStr(vchPubKey))); + obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); + return obj; + } + + Object operator()(const CScriptID &scriptID) const { + Object obj; + obj.push_back(Pair("isscript", true)); + CScript subscript; + pwalletMain->GetCScript(scriptID, subscript); + std::vector addresses; + txnouttype whichType; + int nRequired; + ExtractDestinations(subscript, whichType, addresses, nRequired); + obj.push_back(Pair("script", GetTxnOutputType(whichType))); + Array a; + BOOST_FOREACH(const CTxDestination& addr, addresses) + a.push_back(CBitcoinAddress(addr).ToString()); + obj.push_back(Pair("addresses", a)); + if (whichType == TX_MULTISIG) + obj.push_back(Pair("sigsrequired", nRequired)); + return obj; + } +}; + +Value validateaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "validateaddress \n" + "Return information about ."); + + CBitcoinAddress address(params[0].get_str()); + bool isValid = address.IsValid(); + + Object ret; + ret.push_back(Pair("isvalid", isValid)); + if (isValid) + { + CTxDestination dest = address.Get(); + string currentAddress = address.ToString(); + ret.push_back(Pair("address", currentAddress)); + bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false; + ret.push_back(Pair("ismine", fMine)); + if (fMine) { + Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); + ret.insert(ret.end(), detail.begin(), detail.end()); + } + if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); + } + return ret; +} + +Value lockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "lockunspent unlock? [array-of-Objects]\n" + "Updates list of temporarily unspendable outputs."); + + if (params.size() == 1) + RPCTypeCheck(params, list_of(bool_type)); + else + RPCTypeCheck(params, list_of(bool_type)(array_type)); + + bool fUnlock = params[0].get_bool(); + + if (params.size() == 1) { + if (fUnlock) + pwalletMain->UnlockAllCoins(); + return true; + } + + Array outputs = params[1].get_array(); + BOOST_FOREACH(Value& output, outputs) + { + if (output.type() != obj_type) + throw JSONRPCError(-8, "Invalid parameter, expected object"); + const Object& o = output.get_obj(); + + RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type)); + + string txid = find_value(o, "txid").get_str(); + if (!IsHex(txid)) + throw JSONRPCError(-8, "Invalid parameter, expected hex txid"); + + int nOutput = find_value(o, "vout").get_int(); + if (nOutput < 0) + throw JSONRPCError(-8, "Invalid parameter, vout must be positive"); + + COutPoint outpt(uint256(txid), nOutput); + + if (fUnlock) + pwalletMain->UnlockCoin(outpt); + else + pwalletMain->LockCoin(outpt); + } + + return true; +} + +Value listlockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "listlockunspent\n" + "Returns list of temporarily unspendable outputs."); + + vector vOutpts; + pwalletMain->ListLockedCoins(vOutpts); + + Array ret; + + BOOST_FOREACH(COutPoint &outpt, vOutpts) { + Object o; + + o.push_back(Pair("txid", outpt.hash.GetHex())); + o.push_back(Pair("vout", (int)outpt.n)); + ret.push_back(o); + } + + return ret; +} + diff --git a/src/script.cpp b/src/script.cpp index b32180c..b411666 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include @@ -18,7 +16,7 @@ using namespace boost; #include "sync.h" #include "util.h" -bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); @@ -56,15 +54,6 @@ bool CastToBool(const valtype& vch) return false; } -void MakeSameSize(valtype& vch1, valtype& vch2) -{ - // Lengthen the shorter one - if (vch1.size() < vch2.size()) - vch1.resize(vch2.size(), 0); - if (vch2.size() < vch1.size()) - vch2.resize(vch1.size(), 0); -} - // @@ -238,7 +227,69 @@ const char* GetOpName(opcodetype opcode) } } -bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType) +bool IsCanonicalPubKey(const valtype &vchPubKey) { + if (vchPubKey.size() < 33) + return error("Non-canonical public key: too short"); + if (vchPubKey[0] == 0x04) { + if (vchPubKey.size() != 65) + return error("Non-canonical public key: invalid length for uncompressed key"); + } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { + if (vchPubKey.size() != 33) + return error("Non-canonical public key: invalid length for compressed key"); + } else { + return error("Non-canonical public key: compressed nor uncompressed"); + } + return true; +} + +bool IsCanonicalSignature(const valtype &vchSig) { + // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 + // A canonical signature exists of: <30> <02> <02> + // Where R and S are not negative (their first byte has its highest bit not set), and not + // excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, + // in which case a single 0 byte is necessary and even required). + if (vchSig.size() < 9) + return error("Non-canonical signature: too short"); + if (vchSig.size() > 73) + return error("Non-canonical signature: too long"); + unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); + if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) + return error("Non-canonical signature: unknown hashtype byte"); + if (vchSig[0] != 0x30) + return error("Non-canonical signature: wrong type"); + if (vchSig[1] != vchSig.size()-3) + return error("Non-canonical signature: wrong length marker"); + unsigned int nLenR = vchSig[3]; + if (5 + nLenR >= vchSig.size()) + return error("Non-canonical signature: S length misplaced"); + unsigned int nLenS = vchSig[5+nLenR]; + if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) + return error("Non-canonical signature: R+S length mismatch"); + + const unsigned char *R = &vchSig[4]; + if (R[-2] != 0x02) + return error("Non-canonical signature: R value type mismatch"); + if (nLenR == 0) + return error("Non-canonical signature: R length is zero"); + if (R[0] & 0x80) + return error("Non-canonical signature: R value negative"); + if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) + return error("Non-canonical signature: R value excessively padded"); + + const unsigned char *S = &vchSig[6+nLenR]; + if (S[-2] != 0x02) + return error("Non-canonical signature: S value type mismatch"); + if (nLenS == 0) + return error("Non-canonical signature: S length is zero"); + if (S[0] & 0x80) + return error("Non-canonical signature: S value negative"); + if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) + return error("Non-canonical signature: S value excessively padded"); + + return true; +} + +bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); @@ -251,7 +302,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if (script.size() > 10000) return false; int nOpCount = 0; - + bool fStrictEncodings = flags & SCRIPT_VERIFY_STRICTENC; try { @@ -264,7 +315,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // if (!script.GetOp(pc, opcode, vchPushValue)) return false; - if (vchPushValue.size() > 520) + if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) return false; if (opcode > OP_16 && ++nOpCount > 201) return false; @@ -284,7 +335,7 @@ bool EvalScript(vector >& stack, const CScript& script, co opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) - return false; + return false; // Disabled opcodes. if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); @@ -582,64 +633,6 @@ bool EvalScript(vector >& stack, const CScript& script, co break; - // - // Splice ops - // - case OP_CAT: - { - // (x1 x2 -- out) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - vch1.insert(vch1.end(), vch2.begin(), vch2.end()); - popstack(stack); - if (stacktop(-1).size() > 520) - return false; - } - break; - - case OP_SUBSTR: - { - // (in begin size -- out) - if (stack.size() < 3) - return false; - valtype& vch = stacktop(-3); - int nBegin = CastToBigNum(stacktop(-2)).getint(); - int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); - if (nBegin < 0 || nEnd < nBegin) - return false; - if (nBegin > (int)vch.size()) - nBegin = vch.size(); - if (nEnd > (int)vch.size()) - nEnd = vch.size(); - vch.erase(vch.begin() + nEnd, vch.end()); - vch.erase(vch.begin(), vch.begin() + nBegin); - popstack(stack); - popstack(stack); - } - break; - - case OP_LEFT: - case OP_RIGHT: - { - // (in size -- out) - if (stack.size() < 2) - return false; - valtype& vch = stacktop(-2); - int nSize = CastToBigNum(stacktop(-1)).getint(); - if (nSize < 0) - return false; - if (nSize > (int)vch.size()) - nSize = vch.size(); - if (opcode == OP_LEFT) - vch.erase(vch.begin() + nSize, vch.end()); - else - vch.erase(vch.begin(), vch.end() - nSize); - popstack(stack); - } - break; - case OP_SIZE: { // (in -- in size) @@ -654,46 +647,6 @@ bool EvalScript(vector >& stack, const CScript& script, co // // Bitwise logic // - case OP_INVERT: - { - // (in - out) - if (stack.size() < 1) - return false; - valtype& vch = stacktop(-1); - for (unsigned int i = 0; i < vch.size(); i++) - vch[i] = ~vch[i]; - } - break; - - case OP_AND: - case OP_OR: - case OP_XOR: - { - // (x1 x2 - out) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - MakeSameSize(vch1, vch2); - if (opcode == OP_AND) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] &= vch2[i]; - } - else if (opcode == OP_OR) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] |= vch2[i]; - } - else if (opcode == OP_XOR) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] ^= vch2[i]; - } - popstack(stack); - } - break; - case OP_EQUAL: case OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL @@ -728,8 +681,6 @@ bool EvalScript(vector >& stack, const CScript& script, co // case OP_1ADD: case OP_1SUB: - case OP_2MUL: - case OP_2DIV: case OP_NEGATE: case OP_ABS: case OP_NOT: @@ -743,8 +694,6 @@ bool EvalScript(vector >& stack, const CScript& script, co { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; - case OP_2MUL: bn <<= 1; break; - case OP_2DIV: bn >>= 1; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; @@ -758,11 +707,6 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_ADD: case OP_SUB: - case OP_MUL: - case OP_DIV: - case OP_MOD: - case OP_LSHIFT: - case OP_RSHIFT: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: @@ -791,33 +735,6 @@ bool EvalScript(vector >& stack, const CScript& script, co bn = bn1 - bn2; break; - case OP_MUL: - if (!BN_mul(&bn, &bn1, &bn2, pctx)) - return false; - break; - - case OP_DIV: - if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) - return false; - break; - - case OP_MOD: - if (!BN_mod(&bn, &bn1, &bn2, pctx)) - return false; - break; - - case OP_LSHIFT: - if (bn2 < bnZero || bn2 > CBigNum(2048)) - return false; - bn = bn1 << bn2.getulong(); - break; - - case OP_RSHIFT: - if (bn2 < bnZero || bn2 > CBigNum(2048)) - return false; - bn = bn1 >> bn2.getulong(); - break; - case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; @@ -924,7 +841,9 @@ bool EvalScript(vector >& stack, const CScript& script, co // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); - bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); + bool fSuccess = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey))); + if (fSuccess) + fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); popstack(stack); popstack(stack); @@ -984,8 +903,11 @@ bool EvalScript(vector >& stack, const CScript& script, co valtype& vchPubKey = stacktop(-ikey); // Check signature - if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType)) - { + bool fOk = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey))); + if (fOk) + fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); + + if (fOk) { isig++; nSigsCount--; } @@ -1072,7 +994,7 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int } else if ((nHashType & 0x1f) == SIGHASH_SINGLE) { - // Only lockin the txout payee at same index as txin + // Only lock-in the txout payee at same index as txin unsigned int nOut = nIn; if (nOut >= txTmp.vout.size()) { @@ -1097,10 +1019,9 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int } // Serialize and hash - CDataStream ss(SER_GETHASH, 0); - ss.reserve(10000); + CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; - return Hash(ss.begin(), ss.end()); + return ss.GetHash(); } @@ -1112,15 +1033,15 @@ class CSignatureCache { private: // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple, std::vector > sigdata_type; + typedef boost::tuple, CPubKey> sigdata_type; std::set< sigdata_type> setValid; - CCriticalSection cs_sigcache; + boost::shared_mutex cs_sigcache; public: bool - Get(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { - LOCK(cs_sigcache); + boost::shared_lock lock(cs_sigcache); sigdata_type k(hash, vchSig, pubKey); std::set::iterator mi = setValid.find(k); @@ -1129,8 +1050,7 @@ public: return false; } - void - Set(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + void Set(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { // DoS prevention: limit cache size to less than 10MB // (~200 bytes per cache entry times 50,000 entries) @@ -1139,7 +1059,7 @@ public: int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); if (nMaxCacheSize <= 0) return; - LOCK(cs_sigcache); + boost::unique_lock lock(cs_sigcache); while (static_cast(setValid.size()) > nMaxCacheSize) { @@ -1161,11 +1081,15 @@ public: } }; -bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, - const CTransaction& txTo, unsigned int nIn, int nHashType) +bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, + const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) { static CSignatureCache signatureCache; + CPubKey pubkey(vchPubKey); + if (!pubkey.IsValid()) + return false; + // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) return false; @@ -1177,17 +1101,15 @@ bool CheckSig(vector vchSig, vector vchPubKey, CSc uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (signatureCache.Get(sighash, vchSig, vchPubKey)) + if (signatureCache.Get(sighash, vchSig, pubkey)) return true; - CKey key; - if (!key.SetPubKey(vchPubKey)) + if (!pubkey.Verify(sighash, vchSig)) return false; - if (!key.Verify(sighash, vchSig)) - return false; + if (!(flags & SCRIPT_VERIFY_NOCACHE)) + signatureCache.Set(sighash, vchSig, pubkey); - signatureCache.Set(sighash, vchSig, vchPubKey); return true; } @@ -1274,7 +1196,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector& multisigdata, const CKeyStore& keystore, uint2 // Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. // Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), // unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. -// Returns false if scriptPubKey could not be completely satisified. +// Returns false if scriptPubKey could not be completely satisfied. // bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet, txnouttype& whichTypeRet) @@ -1553,14 +1475,14 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto } bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType) + unsigned int flags, int nHashType) { vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType)) + if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType)) return false; - if (fValidatePayToScriptHash) + if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType)) + if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags, nHashType)) return false; if (stack.empty()) return false; @@ -1569,16 +1491,21 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C return false; // Additional validation for spend-to-script-hash transactions: - if (fValidatePayToScriptHash && scriptPubKey.IsPayToScriptHash()) + if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only return false; // or validation fails + // stackCopy cannot be empty here, because if it was the + // P2SH HASH <> EQUAL scriptPubKey would be evaluated with + // an empty stack and the EvalScript above would return false. + assert(!stackCopy.empty()); + const valtype& pubKeySerialized = stackCopy.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType)) + if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags, nHashType)) return false; if (stackCopy.empty()) return false; @@ -1621,7 +1548,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, 0); + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) @@ -1634,20 +1561,6 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); } -bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType) -{ - assert(nIn < txTo.vin.size()); - const CTxIn& txin = txTo.vin[nIn]; - if (txin.prevout.n >= txFrom.vout.size()) - return false; - const CTxOut& txout = txFrom.vout[txin.prevout.n]; - - if (txin.prevout.hash != txFrom.GetHash()) - return false; - - return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType); -} - static CScript PushAll(const vector& values) { CScript result; @@ -1686,7 +1599,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0)) + if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0)) { sigs[pubkey] = sig; break; @@ -1735,7 +1648,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, return PushAll(sigs1); else { - // Recurse to combine: + // Recur to combine: valtype spk = sigs1.back(); CScript pubKey2(spk.begin(), spk.end()); @@ -1763,9 +1676,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign Solver(scriptPubKey, txType, vSolutions); vector stack1; - EvalScript(stack1, scriptSig1, CTransaction(), 0, 0); + EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); vector stack2; - EvalScript(stack2, scriptSig2, CTransaction(), 0, 0); + EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); } @@ -1813,7 +1726,7 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return 0; } - /// ... and return it's opcount: + /// ... and return its opcount: CScript subscript(data.begin(), data.end()); return subscript.GetSigOpCount(true); } @@ -1857,12 +1770,133 @@ void CScript::SetDestination(const CTxDestination& dest) boost::apply_visitor(CScriptVisitor(this), dest); } -void CScript::SetMultisig(int nRequired, const std::vector& keys) +void CScript::SetMultisig(int nRequired, const std::vector& keys) { this->clear(); *this << EncodeOP_N(nRequired); - BOOST_FOREACH(const CKey& key, keys) - *this << key.GetPubKey(); + BOOST_FOREACH(const CPubKey& key, keys) + *this << key; *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; } + +bool CScriptCompressor::IsToKeyID(CKeyID &hash) const +{ + if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 + && script[2] == 20 && script[23] == OP_EQUALVERIFY + && script[24] == OP_CHECKSIG) { + memcpy(&hash, &script[3], 20); + return true; + } + return false; +} + +bool CScriptCompressor::IsToScriptID(CScriptID &hash) const +{ + if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 + && script[22] == OP_EQUAL) { + memcpy(&hash, &script[2], 20); + return true; + } + return false; +} + +bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const +{ + if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG + && (script[1] == 0x02 || script[1] == 0x03)) { + pubkey.Set(&script[1], &script[34]); + return true; + } + if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG + && script[1] == 0x04) { + pubkey.Set(&script[1], &script[66]); + return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible + } + return false; +} + +bool CScriptCompressor::Compress(std::vector &out) const +{ + CKeyID keyID; + if (IsToKeyID(keyID)) { + out.resize(21); + out[0] = 0x00; + memcpy(&out[1], &keyID, 20); + return true; + } + CScriptID scriptID; + if (IsToScriptID(scriptID)) { + out.resize(21); + out[0] = 0x01; + memcpy(&out[1], &scriptID, 20); + return true; + } + CPubKey pubkey; + if (IsToPubKey(pubkey)) { + out.resize(33); + memcpy(&out[1], &pubkey[1], 32); + if (pubkey[0] == 0x02 || pubkey[0] == 0x03) { + out[0] = pubkey[0]; + return true; + } else if (pubkey[0] == 0x04) { + out[0] = 0x04 | (pubkey[64] & 0x01); + return true; + } + } + return false; +} + +unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const +{ + if (nSize == 0 || nSize == 1) + return 20; + if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5) + return 32; + return 0; +} + +bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector &in) +{ + switch(nSize) { + case 0x00: + script.resize(25); + script[0] = OP_DUP; + script[1] = OP_HASH160; + script[2] = 20; + memcpy(&script[3], &in[0], 20); + script[23] = OP_EQUALVERIFY; + script[24] = OP_CHECKSIG; + return true; + case 0x01: + script.resize(23); + script[0] = OP_HASH160; + script[1] = 20; + memcpy(&script[2], &in[0], 20); + script[22] = OP_EQUAL; + return true; + case 0x02: + case 0x03: + script.resize(35); + script[0] = 33; + script[1] = nSize; + memcpy(&script[2], &in[0], 32); + script[34] = OP_CHECKSIG; + return true; + case 0x04: + case 0x05: + unsigned char vch[33] = {}; + vch[0] = nSize - 2; + memcpy(&vch[1], &in[0], 32); + CPubKey pubkey(&vch[0], &vch[33]); + if (!pubkey.Decompress()) + return false; + assert(pubkey.size() == 65); + script.resize(67); + script[0] = 65; + memcpy(&script[1], pubkey.begin(), 65); + script[66] = OP_CHECKSIG; + return true; + } + return false; +} diff --git a/src/script.h b/src/script.h index 9e0d69a..3cbb2cf 100644 --- a/src/script.h +++ b/src/script.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef H_BITCOIN_SCRIPT @@ -16,8 +14,11 @@ #include "keystore.h" #include "bignum.h" +class CCoins; class CTransaction; +static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes + /** Signature hash types/flags */ enum { @@ -27,6 +28,14 @@ enum SIGHASH_ANYONECANPAY = 0x80, }; +/** Script verification flags */ +enum +{ + SCRIPT_VERIFY_NONE = 0, + SCRIPT_VERIFY_P2SH = (1U << 0), + SCRIPT_VERIFY_STRICTENC = (1U << 1), + SCRIPT_VERIFY_NOCACHE = (1U << 2), +}; enum txnouttype { @@ -339,8 +348,10 @@ public: CScript& operator<<(const CPubKey& key) { - std::vector vchKey = key.Raw(); - return (*this) << vchKey; + assert(key.size() < OP_PUSHDATA1); + insert(end(), (unsigned char)key.size()); + insert(end(), key.begin(), key.end()); + return *this; } CScript& operator<<(const CBigNum& b) @@ -380,7 +391,7 @@ public: { // I'm not sure if this should push the script or concatenate scripts. // If there's ever a use for pushing a script onto a script, delete this member fn - assert(!"warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate"); + assert(!"Warning: Pushing a CScript onto a CScript with << is probably not intended, use + to concatenate!"); return *this; } @@ -428,7 +439,7 @@ public: // Immediate operand if (opcode <= OP_PUSHDATA4) { - unsigned int nSize; + unsigned int nSize = 0; if (opcode < OP_PUSHDATA1) { nSize = opcode; @@ -539,7 +550,7 @@ public: void SetDestination(const CTxDestination& address); - void SetMultisig(int nRequired, const std::vector& keys); + void SetMultisig(int nRequired, const std::vector& keys); void PrintHex() const @@ -581,11 +592,83 @@ public: } }; +/** Compact serializer for scripts. + * + * It detects common cases and encodes them much more efficiently. + * 3 special cases are defined: + * * Pay to pubkey hash (encoded as 21 bytes) + * * Pay to script hash (encoded as 21 bytes) + * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) + * + * Other scripts up to 121 bytes require 1 byte + script length. Above + * that, scripts up to 16505 bytes require 2 bytes + script length. + */ +class CScriptCompressor +{ +private: + // make this static for now (there are only 6 special scripts defined) + // this can potentially be extended together with a new nVersion for + // transactions, in which case this value becomes dependent on nVersion + // and nHeight of the enclosing transaction. + static const unsigned int nSpecialScripts = 6; + CScript &script; +protected: + // These check for scripts for which a special case with a shorter encoding is defined. + // They are implemented separately from the CScript test, as these test for exact byte + // sequence correspondences, and are more strict. For example, IsToPubKey also verifies + // whether the public key is valid (as invalid ones cannot be represented in compressed + // form). + bool IsToKeyID(CKeyID &hash) const; + bool IsToScriptID(CScriptID &hash) const; + bool IsToPubKey(CPubKey &pubkey) const; + bool Compress(std::vector &out) const; + unsigned int GetSpecialSize(unsigned int nSize) const; + bool Decompress(unsigned int nSize, const std::vector &out); +public: + CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } + unsigned int GetSerializeSize(int nType, int nVersion) const { + std::vector compr; + if (Compress(compr)) + return compr.size(); + unsigned int nSize = script.size() + nSpecialScripts; + return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); + } -bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType); + template + void Serialize(Stream &s, int nType, int nVersion) const { + std::vector compr; + if (Compress(compr)) { + s << CFlatData(&compr[0], &compr[compr.size()]); + return; + } + unsigned int nSize = script.size() + nSpecialScripts; + s << VARINT(nSize); + s << CFlatData(&script[0], &script[script.size()]); + } + + template + void Unserialize(Stream &s, int nType, int nVersion) { + unsigned int nSize = 0; + s >> VARINT(nSize); + if (nSize < nSpecialScripts) { + std::vector vch(GetSpecialSize(nSize), 0x00); + s >> REF(CFlatData(&vch[0], &vch[vch.size()])); + Decompress(nSize, vch); + return; + } + nSize -= nSpecialScripts; + script.resize(nSize); + s >> REF(CFlatData(&script[0], &script[script.size()])); + } +}; + +bool IsCanonicalPubKey(const std::vector &vchPubKey); +bool IsCanonicalSignature(const std::vector &vchSig); + +bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions); bool IsStandard(const CScript& scriptPubKey); @@ -595,9 +678,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); -bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); // Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, // combine them intelligently and return the result. diff --git a/src/scrypt-sse2.cpp b/src/scrypt-sse2.cpp new file mode 100644 index 0000000..711dfa9 --- /dev/null +++ b/src/scrypt-sse2.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2009 Colin Percival, 2011 ArtForz, 2012-2013 pooler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include "scrypt.h" +#include +#include +#include +#include + +#include + +static inline void xor_salsa8_sse2(__m128i B[4], const __m128i Bx[4]) +{ + __m128i X0, X1, X2, X3; + __m128i T; + int i; + + X0 = B[0] = _mm_xor_si128(B[0], Bx[0]); + X1 = B[1] = _mm_xor_si128(B[1], Bx[1]); + X2 = B[2] = _mm_xor_si128(B[2], Bx[2]); + X3 = B[3] = _mm_xor_si128(B[3], Bx[3]); + + for (i = 0; i < 8; i += 2) { + /* Operate on "columns". */ + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + + /* Operate on "rows". */ + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + } + + B[0] = _mm_add_epi32(B[0], X0); + B[1] = _mm_add_epi32(B[1], X1); + B[2] = _mm_add_epi32(B[2], X2); + B[3] = _mm_add_epi32(B[3], X3); +} + +void scrypt_1024_1_1_256_sp_sse2(const char *input, char *output, char *scratchpad) +{ + uint8_t B[128]; + union { + __m128i i128[8]; + uint32_t u32[32]; + } X; + __m128i *V; + uint32_t i, j, k; + + V = (__m128i *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128); + + for (k = 0; k < 2; k++) { + for (i = 0; i < 16; i++) { + X.u32[k * 16 + i] = le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + for (i = 0; i < 1024; i++) { + for (k = 0; k < 8; k++) + V[i * 8 + k] = X.i128[k]; + xor_salsa8_sse2(&X.i128[0], &X.i128[4]); + xor_salsa8_sse2(&X.i128[4], &X.i128[0]); + } + for (i = 0; i < 1024; i++) { + j = 8 * (X.u32[16] & 1023); + for (k = 0; k < 8; k++) + X.i128[k] = _mm_xor_si128(X.i128[k], V[j + k]); + xor_salsa8_sse2(&X.i128[0], &X.i128[4]); + xor_salsa8_sse2(&X.i128[4], &X.i128[0]); + } + + for (k = 0; k < 2; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], X.u32[k * 16 + i]); + } + } + + PBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32); +} diff --git a/src/scrypt.cpp b/src/scrypt.cpp new file mode 100644 index 0000000..9131d28 --- /dev/null +++ b/src/scrypt.cpp @@ -0,0 +1,329 @@ +/* + * Copyright 2009 Colin Percival, 2011 ArtForz, 2012-2013 pooler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include "scrypt.h" +#include "util.h" +#include +#include +#include +#include + +#if defined(USE_SSE2) && !defined(USE_SSE2_ALWAYS) +#ifdef _MSC_VER +// MSVC 64bit is unable to use inline asm +#include +#else +// GCC Linux or i686-w64-mingw32 +#include +#endif +#endif + +static inline uint32_t be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void be32enc(void *pp, uint32_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +/* Initialize an HMAC-SHA256 operation with the given key. */ +static void +HMAC_SHA256_Init(HMAC_SHA256_CTX *ctx, const void *_K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char *K = (const unsigned char *)_K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Update(HMAC_SHA256_CTX *ctx, const void *in, size_t len) +{ + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX *ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} + +#define ROTL(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) + +static inline void xor_salsa8(uint32_t B[16], const uint32_t Bx[16]) +{ + uint32_t x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15; + int i; + + x00 = (B[ 0] ^= Bx[ 0]); + x01 = (B[ 1] ^= Bx[ 1]); + x02 = (B[ 2] ^= Bx[ 2]); + x03 = (B[ 3] ^= Bx[ 3]); + x04 = (B[ 4] ^= Bx[ 4]); + x05 = (B[ 5] ^= Bx[ 5]); + x06 = (B[ 6] ^= Bx[ 6]); + x07 = (B[ 7] ^= Bx[ 7]); + x08 = (B[ 8] ^= Bx[ 8]); + x09 = (B[ 9] ^= Bx[ 9]); + x10 = (B[10] ^= Bx[10]); + x11 = (B[11] ^= Bx[11]); + x12 = (B[12] ^= Bx[12]); + x13 = (B[13] ^= Bx[13]); + x14 = (B[14] ^= Bx[14]); + x15 = (B[15] ^= Bx[15]); + for (i = 0; i < 8; i += 2) { + /* Operate on columns. */ + x04 ^= ROTL(x00 + x12, 7); x09 ^= ROTL(x05 + x01, 7); + x14 ^= ROTL(x10 + x06, 7); x03 ^= ROTL(x15 + x11, 7); + + x08 ^= ROTL(x04 + x00, 9); x13 ^= ROTL(x09 + x05, 9); + x02 ^= ROTL(x14 + x10, 9); x07 ^= ROTL(x03 + x15, 9); + + x12 ^= ROTL(x08 + x04, 13); x01 ^= ROTL(x13 + x09, 13); + x06 ^= ROTL(x02 + x14, 13); x11 ^= ROTL(x07 + x03, 13); + + x00 ^= ROTL(x12 + x08, 18); x05 ^= ROTL(x01 + x13, 18); + x10 ^= ROTL(x06 + x02, 18); x15 ^= ROTL(x11 + x07, 18); + + /* Operate on rows. */ + x01 ^= ROTL(x00 + x03, 7); x06 ^= ROTL(x05 + x04, 7); + x11 ^= ROTL(x10 + x09, 7); x12 ^= ROTL(x15 + x14, 7); + + x02 ^= ROTL(x01 + x00, 9); x07 ^= ROTL(x06 + x05, 9); + x08 ^= ROTL(x11 + x10, 9); x13 ^= ROTL(x12 + x15, 9); + + x03 ^= ROTL(x02 + x01, 13); x04 ^= ROTL(x07 + x06, 13); + x09 ^= ROTL(x08 + x11, 13); x14 ^= ROTL(x13 + x12, 13); + + x00 ^= ROTL(x03 + x02, 18); x05 ^= ROTL(x04 + x07, 18); + x10 ^= ROTL(x09 + x08, 18); x15 ^= ROTL(x14 + x13, 18); + } + B[ 0] += x00; + B[ 1] += x01; + B[ 2] += x02; + B[ 3] += x03; + B[ 4] += x04; + B[ 5] += x05; + B[ 6] += x06; + B[ 7] += x07; + B[ 8] += x08; + B[ 9] += x09; + B[10] += x10; + B[11] += x11; + B[12] += x12; + B[13] += x13; + B[14] += x14; + B[15] += x15; +} + +void scrypt_1024_1_1_256_sp_generic(const char *input, char *output, char *scratchpad) +{ + uint8_t B[128]; + uint32_t X[32]; + uint32_t *V; + uint32_t i, j, k; + + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128); + + for (k = 0; k < 32; k++) + X[k] = le32dec(&B[4 * k]); + + for (i = 0; i < 1024; i++) { + memcpy(&V[i * 32], X, 128); + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + for (i = 0; i < 1024; i++) { + j = 32 * (X[16] & 1023); + for (k = 0; k < 32; k++) + X[k] ^= V[j + k]; + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + + for (k = 0; k < 32; k++) + le32enc(&B[4 * k], X[k]); + + PBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32); +} + +#if defined(USE_SSE2) +// By default, set to generic scrypt function. This will prevent crash in case when scrypt_detect_sse2() wasn't called +void (*scrypt_1024_1_1_256_sp_detected)(const char *input, char *output, char *scratchpad) = &scrypt_1024_1_1_256_sp_generic; + +void scrypt_detect_sse2() +{ +#if defined(USE_SSE2_ALWAYS) + printf("scrypt: using scrypt-sse2 as built.\n"); +#else // USE_SSE2_ALWAYS + // 32bit x86 Linux or Windows, detect cpuid features + unsigned int cpuid_edx=0; +#if defined(_MSC_VER) + // MSVC + int x86cpuid[4]; + __cpuid(x86cpuid, 1); + cpuid_edx = (unsigned int)buffer[3]; +#else // _MSC_VER + // Linux or i686-w64-mingw32 (gcc-4.6.3) + unsigned int eax, ebx, ecx; + __get_cpuid(1, &eax, &ebx, &ecx, &cpuid_edx); +#endif // _MSC_VER + + if (cpuid_edx & 1<<26) + { + scrypt_1024_1_1_256_sp_detected = &scrypt_1024_1_1_256_sp_sse2; + printf("scrypt: using scrypt-sse2 as detected.\n"); + } + else + { + scrypt_1024_1_1_256_sp_detected = &scrypt_1024_1_1_256_sp_generic; + printf("scrypt: using scrypt-generic, SSE2 unavailable.\n"); + } +#endif // USE_SSE2_ALWAYS +} +#endif + +void scrypt_1024_1_1_256(const char *input, char *output) +{ + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + scrypt_1024_1_1_256_sp(input, output, scratchpad); +} diff --git a/src/scrypt.h b/src/scrypt.h index 3a08617..5431fb6 100644 --- a/src/scrypt.h +++ b/src/scrypt.h @@ -1,17 +1,45 @@ #ifndef SCRYPT_H #define SCRYPT_H +#include +#include -#ifdef __cplusplus -extern "C" { +static const int SCRYPT_SCRATCHPAD_SIZE = 131072 + 63; + +void scrypt_1024_1_1_256(const char *input, char *output); +void scrypt_1024_1_1_256_sp_generic(const char *input, char *output, char *scratchpad); + +#if defined(USE_SSE2) +#if defined(_M_X64) || defined(__x86_64__) || defined(_M_AMD64) || (defined(MAC_OSX) && defined(__i386__)) +#define USE_SSE2_ALWAYS 1 +#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_sse2((input), (output), (scratchpad)) +#else +#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_detected((input), (output), (scratchpad)) #endif -const int SCRYPT_SCRATCHPAD_SIZE = 131072 + 63; +void scrypt_detect_sse2(); +void scrypt_1024_1_1_256_sp_sse2(const char *input, char *output, char *scratchpad); +extern void (*scrypt_1024_1_1_256_sp_detected)(const char *input, char *output, char *scratchpad); +#else +#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_generic((input), (output), (scratchpad)) +#endif -void scrypt_1024_1_1_256_sp(const char *input, char *output, char *scratchpad); -void scrypt_1024_1_1_256(const char *input, char *output); +void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen); -#ifdef __cplusplus +static inline uint32_t le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void le32enc(void *pp, uint32_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; } #endif - -#endif diff --git a/src/serialize.h b/src/serialize.h index 9cf1de4..eac4e06 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SERIALIZE_H @@ -52,10 +50,6 @@ enum SER_NETWORK = (1 << 0), SER_DISK = (1 << 1), SER_GETHASH = (1 << 2), - - // modifiers - SER_SKIPSIG = (1 << 16), - SER_BLOCKHEADERONLY = (1 << 17), }; #define IMPLEMENT_SERIALIZE(statements) \ @@ -240,12 +234,77 @@ uint64 ReadCompactSize(Stream& is) return nSizeRet; } +// Variable-length integers: bytes are a MSB base-128 encoding of the number. +// The high bit in each byte signifies whether another digit follows. To make +// the encoding is one-to-one, one is subtracted from all but the last digit. +// Thus, the byte sequence a[] with length len, where all but the last byte +// has bit 128 set, encodes the number: +// +// (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) +// +// Properties: +// * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) +// * Every integer has exactly one encoding +// * Encoding does not depend on size of original integer type +// * No redundancy: every (infinite) byte sequence corresponds to a list +// of encoded integers. +// +// 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] +// 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] +template +inline unsigned int GetSizeOfVarInt(I n) +{ + int nRet = 0; + while(true) { + nRet++; + if (n <= 0x7F) + break; + n = (n >> 7) - 1; + } + return nRet; +} -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +template +void WriteVarInt(Stream& os, I n) +{ + unsigned char tmp[(sizeof(n)*8+6)/7]; + int len=0; + while(true) { + tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); + if (n <= 0x7F) + break; + n = (n >> 7) - 1; + len++; + } + do { + WRITEDATA(os, tmp[len]); + } while(len--); +} + +template +I ReadVarInt(Stream& is) +{ + I n = 0; + while(true) { + unsigned char chData; + READDATA(is, chData); + n = (n << 7) | (chData & 0x7F); + if (chData & 0x80) + n++; + else + return n; + } +} + +#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +#define VARINT(obj) REF(WrapVarInt(REF(obj))) /** Wrapper for serializing arrays and POD. - * There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it. */ class CFlatData { @@ -277,6 +336,32 @@ public: } }; +template +class CVarInt +{ +protected: + I &n; +public: + CVarInt(I& nIn) : n(nIn) { } + + unsigned int GetSerializeSize(int, int) const { + return GetSizeOfVarInt(n); + } + + template + void Serialize(Stream &s, int, int) const { + WriteVarInt(s, n); + } + + template + void Unserialize(Stream& s, int, int) { + n = ReadVarInt(s); + } +}; + +template +CVarInt WrapVarInt(I& n) { return CVarInt(n); } + // // Forward declarations // @@ -704,6 +789,7 @@ struct ser_streamplaceholder +typedef std::vector > CSerializeData; /** Double ended buffer combining vector and stream-like interfaces. * @@ -713,7 +799,7 @@ struct ser_streamplaceholder class CDataStream { protected: - typedef std::vector > vector_type; + typedef CSerializeData vector_type; vector_type vch; unsigned int nReadPos; short state; @@ -809,19 +895,6 @@ public: 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); } - void insert(iterator it, const_iterator first, const_iterator last) - { - 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 - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) { assert(last - first >= 0); @@ -1010,58 +1083,12 @@ public: ::Unserialize(*this, obj, nType, nVersion); return (*this); } -}; -#ifdef TESTCDATASTREAM -// VC6sp6 -// CDataStream: -// n=1000 0 seconds -// n=2000 0 seconds -// n=4000 0 seconds -// n=8000 0 seconds -// n=16000 0 seconds -// n=32000 0 seconds -// n=64000 1 seconds -// n=128000 1 seconds -// n=256000 2 seconds -// n=512000 4 seconds -// n=1024000 8 seconds -// n=2048000 16 seconds -// n=4096000 32 seconds -// stringstream: -// n=1000 1 seconds -// n=2000 1 seconds -// n=4000 13 seconds -// n=8000 87 seconds -// n=16000 400 seconds -// n=32000 1660 seconds -// n=64000 6749 seconds -// n=128000 27241 seconds -// n=256000 109804 seconds -#include -int main(int argc, char *argv[]) -{ - vector vch(0xcc, 250); - printf("CDataStream:\n"); - for (int n = 1000; n <= 4500000; n *= 2) - { - CDataStream ss; - time_t nStart = time(NULL); - for (int i = 0; i < n; i++) - ss.write((char*)&vch[0], vch.size()); - printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); + void GetAndClear(CSerializeData &data) { + vch.swap(data); + CSerializeData().swap(vch); } - printf("stringstream:\n"); - for (int n = 1000; n <= 4500000; n *= 2) - { - stringstream ss; - time_t nStart = time(NULL); - for (int i = 0; i < n; i++) - ss.write((char*)&vch[0], vch.size()); - printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); - } -} -#endif +}; @@ -1187,4 +1214,148 @@ public: } }; +/** Wrapper around a FILE* that implements a ring buffer to + * deserialize from. It guarantees the ability to rewind + * a given number of bytes. */ +class CBufferedFile +{ +private: + FILE *src; // source file + uint64 nSrcPos; // how many bytes have been read from source + uint64 nReadPos; // how many bytes have been read from this + uint64 nReadLimit; // up to which position we're allowed to read + uint64 nRewind; // how many bytes we guarantee to rewind + std::vector vchBuf; // the buffer + + short state; + short exceptmask; + +protected: + void setstate(short bits, const char *psz) { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); + } + + // read data from the source to fill the buffer + bool Fill() { + unsigned int pos = nSrcPos % vchBuf.size(); + unsigned int readNow = vchBuf.size() - pos; + unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind; + if (nAvail < readNow) + readNow = nAvail; + if (readNow == 0) + return false; + size_t read = fread((void*)&vchBuf[pos], 1, readNow, src); + if (read == 0) { + setstate(std::ios_base::failbit, feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed"); + return false; + } else { + nSrcPos += read; + return true; + } + } + +public: + int nType; + int nVersion; + + CBufferedFile(FILE *fileIn, uint64 nBufSize, uint64 nRewindIn, int nTypeIn, int nVersionIn) : + src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0), + state(0), exceptmask(std::ios_base::badbit | std::ios_base::failbit), nType(nTypeIn), nVersion(nVersionIn) { + } + + // check whether no error occurred + bool good() const { + return state == 0; + } + + // check whether we're at the end of the source file + bool eof() const { + return nReadPos == nSrcPos && feof(src); + } + + // read a number of bytes + CBufferedFile& 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()) + throw std::ios_base::failure("Read larger than buffer size"); + while (nSize > 0) { + if (nReadPos == nSrcPos) + Fill(); + unsigned int pos = nReadPos % vchBuf.size(); + size_t nNow = nSize; + if (nNow + pos > vchBuf.size()) + nNow = vchBuf.size() - pos; + if (nNow + nReadPos > nSrcPos) + nNow = nSrcPos - nReadPos; + memcpy(pch, &vchBuf[pos], nNow); + nReadPos += nNow; + pch += nNow; + nSize -= nNow; + } + return (*this); + } + + // return the current reading position + uint64 GetPos() { + return nReadPos; + } + + // rewind to a given reading position + bool SetPos(uint64 nPos) { + nReadPos = nPos; + if (nReadPos + nRewind < nSrcPos) { + nReadPos = nSrcPos - nRewind; + return false; + } else if (nReadPos > nSrcPos) { + nReadPos = nSrcPos; + return false; + } else { + return true; + } + } + + bool Seek(uint64 nPos) { + long nLongPos = nPos; + if (nPos != (uint64)nLongPos) + return false; + if (fseek(src, nLongPos, SEEK_SET)) + return false; + nLongPos = ftell(src); + nSrcPos = nLongPos; + nReadPos = nLongPos; + state = 0; + return true; + } + + // prevent reading beyond a certain position + // no argument removes the limit + bool SetLimit(uint64 nPos = (uint64)(-1)) { + if (nPos < nReadPos) + return false; + nReadLimit = nPos; + return true; + } + + template + CBufferedFile& operator>>(T& obj) { + // Unserialize from this stream + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } + + // search for a given byte in the stream, and remain positioned on it + void FindByte(char ch) { + while (true) { + if (nReadPos == nSrcPos) + Fill(); + if (vchBuf[nReadPos % vchBuf.size()] == ch) + break; + nReadPos++; + } + } +}; + #endif diff --git a/src/sync.cpp b/src/sync.cpp index 3702ec2..1ac4403 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -1,6 +1,4 @@ // Copyright (c) 2011-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -107,7 +105,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) static void pop_lock() { - if (fDebug) + if (fDebug) { const CLockLocation& locklocation = (*lockstack).rbegin()->second; printf("Unlocked: %s\n", locklocation.ToString().c_str()); diff --git a/src/sync.h b/src/sync.h index 680ce19..930c9b2 100644 --- a/src/sync.h +++ b/src/sync.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SYNC_H @@ -11,15 +9,36 @@ #include #include #include +#include "threadsafety.h" +// Template mixin that adds -Wthread-safety locking annotations to a +// subset of the mutex API. +template +class LOCKABLE AnnotatedMixin : public PARENT +{ +public: + void lock() EXCLUSIVE_LOCK_FUNCTION() + { + PARENT::lock(); + } + void unlock() UNLOCK_FUNCTION() + { + PARENT::unlock(); + } + bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) + { + return PARENT::try_lock(); + } +}; /** Wrapped boost mutex: supports recursive locking, but no waiting */ -typedef boost::recursive_mutex CCriticalSection; +// TODO: We should move away from using the recursive lock by default. +typedef AnnotatedMixin CCriticalSection; /** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef boost::mutex CWaitableCriticalSection; +typedef AnnotatedMixin CWaitableCriticalSection; #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); @@ -33,52 +52,37 @@ void static inline LeaveCritical() {} void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around boost::interprocess::scoped_lock */ +/** Wrapper around boost::unique_lock */ template class CMutexLock { private: boost::unique_lock lock; -public: void Enter(const char* pszName, const char* pszFile, int nLine) { - if (!lock.owns_lock()) - { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); #ifdef DEBUG_LOCKCONTENTION - if (!lock.try_lock()) - { - PrintLockContention(pszName, pszFile, nLine); -#endif - lock.lock(); -#ifdef DEBUG_LOCKCONTENTION - } -#endif - } - } - - void Leave() - { - if (lock.owns_lock()) + if (!lock.try_lock()) { - lock.unlock(); - LeaveCritical(); + PrintLockContention(pszName, pszFile, nLine); +#endif + lock.lock(); +#ifdef DEBUG_LOCKCONTENTION } +#endif } bool TryEnter(const char* pszName, const char* pszFile, int nLine) { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); + lock.try_lock(); if (!lock.owns_lock()) - { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); - lock.try_lock(); - if (!lock.owns_lock()) - LeaveCritical(); - } + LeaveCritical(); return lock.owns_lock(); } +public: CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) { if (fTry) @@ -97,11 +101,6 @@ public: { return lock.owns_lock(); } - - boost::unique_lock &GetLock() - { - return lock; - } }; typedef CMutexLock CCriticalBlock; diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 4a185b3..2ee6475 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -16,10 +16,10 @@ #include // Tests this internal-to-main.cpp method: -extern bool AddOrphanTx(const CDataStream& vMsg); +extern bool AddOrphanTx(const CTransaction& tx); extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); -extern std::map mapOrphanTransactions; -extern std::map > mapOrphanTransactionsByPrev; +extern std::map mapOrphanTransactions; +extern std::map > mapOrphanTransactionsByPrev; CService ip(uint32_t i) { @@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CNode dummyNode1(INVALID_SOCKET, addr1, "", true); dummyNode1.Misbehaving(100); // Should get banned BOOST_CHECK(CNode::IsBanned(addr1)); - BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned + BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002)); CNode dummyNode2(INVALID_SOCKET, addr2, "", true); @@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be dummyNode2.Misbehaving(50); BOOST_CHECK(CNode::IsBanned(addr2)); -} +} BOOST_AUTO_TEST_CASE(DoS_banscore) { @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits) { using namespace boost::assign; // for 'map_list_of()' - // Timestamps,nBits from the bitcoin blockchain. + // Timestamps,nBits from the bitcoin block chain. // These are the block-chain checkpoint blocks typedef std::map BlockData; BlockData chainData = @@ -129,19 +129,15 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits) // ... but OK if enough time passed for difficulty to adjust downward: BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first)); - } CTransaction RandomOrphan() { - std::map::iterator it; + std::map::iterator it; it = mapOrphanTransactions.lower_bound(GetRandHash()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); - const CDataStream* pvMsg = it->second; - CTransaction tx; - CDataStream(*pvMsg) >> tx; - return tx; + return it->second; } BOOST_AUTO_TEST_CASE(DoS_mapOrphans) @@ -163,9 +159,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + AddOrphanTx(tx); } // ... and 50 that depend on other orphans: @@ -182,9 +176,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); SignSignature(keystore, txPrev, tx, 0); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + AddOrphanTx(tx); } // This really-big orphan should be ignored: @@ -208,9 +200,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) for (unsigned int j = 1; j < tx.vin.size(); j++) tx.vin[j].scriptSig = tx.vin[0].scriptSig; - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - BOOST_CHECK(!AddOrphanTx(ds)); + BOOST_CHECK(!AddOrphanTx(tx)); } // Test LimitOrphanTxSize() function: @@ -231,6 +221,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) key.MakeNewKey(true); CBasicKeyStore keystore; keystore.AddKey(key); + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; // 100 orphan transactions: static const int NPREV=100; @@ -246,9 +237,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + AddOrphanTx(tx); } // Create a transaction that depends on orphans: @@ -278,7 +267,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) mst1 = boost::posix_time::microsec_clock::local_time(); for (unsigned int i = 0; i < 5; i++) for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL)); + BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL)); mst2 = boost::posix_time::microsec_clock::local_time(); msdiff = mst2 - mst1; long nManyValidate = msdiff.total_milliseconds(); @@ -289,13 +278,13 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) // Empty a signature, validation should fail: CScript save = tx.vin[0].scriptSig; tx.vin[0].scriptSig = CScript(); - BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL)); tx.vin[0].scriptSig = save; // Swap signatures, validation should fail: std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); - BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL)); - BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, SIGHASH_ALL)); std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); // Exercise -maxsigcachesize code: @@ -305,7 +294,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0)); BOOST_CHECK(tx.vin[0].scriptSig != oldSig); for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL)); + BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL)); mapArgs.erase("-maxsigcachesize"); LimitOrphanTxSize(0); diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp new file mode 100644 index 0000000..8ac6572 --- /dev/null +++ b/src/test/accounting_tests.cpp @@ -0,0 +1,123 @@ +#include + +#include + +#include "init.h" +#include "wallet.h" +#include "walletdb.h" + +BOOST_AUTO_TEST_SUITE(accounting_tests) + +static void +GetResults(CWalletDB& walletdb, std::map& results) +{ + std::list aes; + + results.clear(); + BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK); + walletdb.ListAccountCreditDebit("", aes); + BOOST_FOREACH(CAccountingEntry& ae, aes) + { + results[ae.nOrderPos] = ae; + } +} + +BOOST_AUTO_TEST_CASE(acc_orderupgrade) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + std::vector vpwtx; + CWalletTx wtx; + CAccountingEntry ae; + std::map results; + + ae.strAccount = ""; + ae.nCreditDebit = 1; + ae.nTime = 1333333333; + ae.strOtherAccount = "b"; + ae.strComment = ""; + walletdb.WriteAccountingEntry(ae); + + wtx.mapValue["comment"] = "z"; + 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"; + walletdb.WriteAccountingEntry(ae); + + GetResults(walletdb, results); + + BOOST_CHECK(pwalletMain->nOrderPosNext == 3); + BOOST_CHECK(2 == results.size()); + BOOST_CHECK(results[0].nTime == 1333333333); + BOOST_CHECK(results[0].strComment.empty()); + BOOST_CHECK(1 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[2].nTime == 1333333336); + BOOST_CHECK(results[2].strOtherAccount == "c"); + + + ae.nTime = 1333333330; + ae.strOtherAccount = "d"; + ae.nOrderPos = pwalletMain->IncOrderPosNext(); + walletdb.WriteAccountingEntry(ae); + + GetResults(walletdb, results); + + BOOST_CHECK(results.size() == 3); + BOOST_CHECK(pwalletMain->nOrderPosNext == 4); + BOOST_CHECK(results[0].nTime == 1333333333); + BOOST_CHECK(1 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[2].nTime == 1333333336); + BOOST_CHECK(results[3].nTime == 1333333330); + BOOST_CHECK(results[3].strComment.empty()); + + + wtx.mapValue["comment"] = "y"; + --wtx.nLockTime; // Just to change the hash :) + pwalletMain->AddToWallet(wtx); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); + vpwtx[1]->nTimeReceived = (unsigned int)1333333336; + + wtx.mapValue["comment"] = "x"; + --wtx.nLockTime; // Just to change the hash :) + pwalletMain->AddToWallet(wtx); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); + vpwtx[2]->nTimeReceived = (unsigned int)1333333329; + vpwtx[2]->nOrderPos = -1; + + GetResults(walletdb, results); + + BOOST_CHECK(results.size() == 3); + BOOST_CHECK(pwalletMain->nOrderPosNext == 6); + BOOST_CHECK(0 == vpwtx[2]->nOrderPos); + BOOST_CHECK(results[1].nTime == 1333333333); + BOOST_CHECK(2 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[3].nTime == 1333333336); + BOOST_CHECK(results[4].nTime == 1333333330); + BOOST_CHECK(results[4].strComment.empty()); + BOOST_CHECK(5 == vpwtx[1]->nOrderPos); + + + ae.nTime = 1333333334; + ae.strOtherAccount = "e"; + ae.nOrderPos = -1; + walletdb.WriteAccountingEntry(ae); + + GetResults(walletdb, results); + + BOOST_CHECK(results.size() == 4); + BOOST_CHECK(pwalletMain->nOrderPosNext == 7); + BOOST_CHECK(0 == vpwtx[2]->nOrderPos); + BOOST_CHECK(results[1].nTime == 1333333333); + BOOST_CHECK(2 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[3].nTime == 1333333336); + BOOST_CHECK(results[3].strComment.empty()); + BOOST_CHECK(results[4].nTime == 1333333330); + BOOST_CHECK(results[4].strComment.empty()); + BOOST_CHECK(results[5].nTime == 1333333334); + BOOST_CHECK(6 == vpwtx[1]->nOrderPos); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp new file mode 100644 index 0000000..f9e2be7 --- /dev/null +++ b/src/test/alert_tests.cpp @@ -0,0 +1,182 @@ +// +// Unit tests for alert system +// + +#include +#include +#include + +#include "alert.h" +#include "serialize.h" +#include "util.h" + +#if 0 +// +// alertTests contains 7 alerts, generated with this code: +// (SignAndSave code not shown, alert signing key is secret) +// +{ + CAlert alert; + alert.nRelayUntil = 60; + alert.nExpiration = 24 * 60 * 60; + alert.nID = 1; + alert.nCancel = 0; // cancels previous messages up to this ID number + alert.nMinVer = 0; // These versions are protocol versions + alert.nMaxVer = 70001; + alert.nPriority = 1; + alert.strComment = "Alert comment"; + alert.strStatusBar = "Alert 1"; + + SignAndSave(alert, "test/alertTests"); + + alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); + alert.strStatusBar = "Alert 1 for Satoshi 0.1.0"; + SignAndSave(alert, "test/alertTests"); + + alert.setSubVer.insert(std::string("/Satoshi:0.2.0/")); + alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0"; + SignAndSave(alert, "test/alertTests"); + + alert.setSubVer.clear(); + ++alert.nID; + alert.nCancel = 1; + alert.nPriority = 100; + alert.strStatusBar = "Alert 2, cancels 1"; + SignAndSave(alert, "test/alertTests"); + + alert.nExpiration += 60; + ++alert.nID; + SignAndSave(alert, "test/alertTests"); + + ++alert.nID; + alert.nMinVer = 11; + alert.nMaxVer = 22; + SignAndSave(alert, "test/alertTests"); + + ++alert.nID; + alert.strStatusBar = "Alert 2 for Satoshi 0.1.0"; + alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); + SignAndSave(alert, "test/alertTests"); + + ++alert.nID; + alert.nMinVer = 0; + alert.nMaxVer = 999999; + alert.strStatusBar = "Evil Alert'; /bin/ls; echo '"; + alert.setSubVer.clear(); + SignAndSave(alert, "test/alertTests"); +} +#endif + +struct ReadAlerts +{ + ReadAlerts() + { + std::string filename("alertTests"); + namespace fs = boost::filesystem; + fs::path testFile = fs::current_path() / "test" / "data" / filename; +#ifdef TEST_DATA_DIR + if (!fs::exists(testFile)) + { + testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; + } +#endif + FILE* fp = fopen(testFile.string().c_str(), "rb"); + if (!fp) return; + + + CAutoFile filein = CAutoFile(fp, SER_DISK, CLIENT_VERSION); + if (!filein) return; + + try { + while (!feof(filein)) + { + CAlert alert; + filein >> alert; + alerts.push_back(alert); + } + } + catch (std::exception) { } + } + ~ReadAlerts() { } + + static std::vector read_lines(boost::filesystem::path filepath) + { + std::vector result; + + std::ifstream f(filepath.string().c_str()); + std::string line; + while (std::getline(f,line)) + result.push_back(line); + + return result; + } + + std::vector alerts; +}; + +BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts) + + +BOOST_AUTO_TEST_CASE(AlertApplies) +{ + SetMockTime(11); + + BOOST_FOREACH(const CAlert& alert, alerts) + { + BOOST_CHECK(alert.CheckSignature()); + } + // Matches: + BOOST_CHECK(alerts[0].AppliesTo(1, "")); + BOOST_CHECK(alerts[0].AppliesTo(70001, "")); + BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/")); + + BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/")); + BOOST_CHECK(alerts[1].AppliesTo(70001, "/Satoshi:0.1.0/")); + + BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/")); + BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/")); + + // Don't match: + BOOST_CHECK(!alerts[0].AppliesTo(-1, "")); + BOOST_CHECK(!alerts[0].AppliesTo(70002, "")); + + BOOST_CHECK(!alerts[1].AppliesTo(1, "")); + BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0")); + BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0")); + BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/")); + BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/")); + BOOST_CHECK(!alerts[1].AppliesTo(70002, "/Satoshi:0.1.0/")); + BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/")); + + BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/")); + + SetMockTime(0); +} + + +// This uses sh 'echo' to test the -alertnotify function, writing to a +// /tmp file. So skip it on Windows: +#ifndef WIN32 +BOOST_AUTO_TEST_CASE(AlertNotify) +{ + SetMockTime(11); + + boost::filesystem::path temp = GetTempPath() / "alertnotify.txt"; + boost::filesystem::remove(temp); + + mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); + + BOOST_FOREACH(CAlert alert, alerts) + alert.ProcessAlert(false); + + std::vector r = read_lines(temp); + BOOST_CHECK_EQUAL(r.size(), 1u); + BOOST_CHECK_EQUAL(r[0], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed + + boost::filesystem::remove(temp); + + SetMockTime(0); +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp new file mode 100644 index 0000000..d5cb8e8 --- /dev/null +++ b/src/test/allocator_tests.cpp @@ -0,0 +1,115 @@ +#include + +#include "init.h" +#include "main.h" +#include "util.h" + +BOOST_AUTO_TEST_SUITE(allocator_tests) + +// 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 +{ +public: + bool Lock(const void *addr, size_t len) + { + 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; + } +}; + +BOOST_AUTO_TEST_CASE(test_LockedPageManagerBase) +{ + const size_t test_page_size = 4096; + LockedPageManagerBase 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(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(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(addr), test_page_size); + addr += test_page_size; + } + /* one very large object, straddling pages */ + lpm.LockRange(reinterpret_cast(test_page_size*600+1), test_page_size*500); + BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size*(600+500))); + /* one very large object, page aligned */ + lpm.LockRange(reinterpret_cast(test_page_size*1200), test_page_size*500-1); + BOOST_CHECK(last_lock_addr == reinterpret_cast(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) + { + lpm.UnlockRange(reinterpret_cast(addr), 33); + addr += 33; + } + addr = test_page_size*100 + 53; + for(int i=0; i<100; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), test_page_size); + addr += test_page_size; + } + addr = test_page_size*300; + for(int i=0; i<100; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), test_page_size); + addr += test_page_size; + } + lpm.UnlockRange(reinterpret_cast(test_page_size*600+1), test_page_size*500); + lpm.UnlockRange(reinterpret_cast(test_page_size*1200), test_page_size*500-1); + + /* Check that everything is released */ + BOOST_CHECK(lpm.GetLockedPageCount() == 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(addr), 0); + addr += 1; + } + BOOST_CHECK(lpm.GetLockedPageCount() == 0); + addr = 0; + for(int i=0; i<1000; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), 0); + addr += 1; + } + BOOST_CHECK(lpm.GetLockedPageCount() == 0); + BOOST_CHECK((last_unlock_len & (test_page_size-1)) == 0); // always unlock entire pages +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 3f265f1..2741672 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -1,87 +1,261 @@ #include +#include "json/json_spirit_reader_template.h" +#include "json/json_spirit_writer_template.h" +#include "json/json_spirit_utils.h" #include "base58.h" +#include "util.h" + +using namespace json_spirit; +extern Array read_json(const std::string& filename); BOOST_AUTO_TEST_SUITE(base58_tests) -// TODO: -// EncodeBase58Check -// DecodeBase58Check -// CBase58Data -// bool SetString(const char* psz) - // bool SetString(const std::string& str) - // std::string ToString() const - // int CompareTo(const CBase58Data& b58) const - // bool operator==(const CBase58Data& b58) const - // bool operator<=(const CBase58Data& b58) const - // bool operator>=(const CBase58Data& b58) const - // bool operator< (const CBase58Data& b58) const - // bool operator> (const CBase58Data& b58) const - -// CBitcoinAddress - // bool SetHash160(const uint160& hash160) - // bool SetPubKey(const std::vector& vchPubKey) - // bool IsValid() const - // CBitcoinAddress() - // CBitcoinAddress(uint160 hash160In) - // CBitcoinAddress(const std::vector& vchPubKey) - // CBitcoinAddress(const std::string& strAddress) - // CBitcoinAddress(const char* pszAddress) - // uint160 GetHash160() const - -#define U(x) (reinterpret_cast(x)) -static struct { - const unsigned char *data; - int size; -} vstrIn[] = { -{U(""), 0}, -{U("\x61"), 1}, -{U("\x62\x62\x62"), 3}, -{U("\x63\x63\x63"), 3}, -{U("\x73\x69\x6d\x70\x6c\x79\x20\x61\x20\x6c\x6f\x6e\x67\x20\x73\x74\x72\x69\x6e\x67"), 20}, -{U("\x00\xeb\x15\x23\x1d\xfc\xeb\x60\x92\x58\x86\xb6\x7d\x06\x52\x99\x92\x59\x15\xae\xb1\x72\xc0\x66\x47"), 25}, -{U("\x51\x6b\x6f\xcd\x0f"), 5}, -{U("\xbf\x4f\x89\x00\x1e\x67\x02\x74\xdd"), 9}, -{U("\x57\x2e\x47\x94"), 4}, -{U("\xec\xac\x89\xca\xd9\x39\x23\xc0\x23\x21"), 10}, -{U("\x10\xc8\x51\x1e"), 4}, -{U("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), 10}, -}; - -const char *vstrOut[] = { -"", -"2g", -"a3gV", -"aPEr", -"2cFupjhnEsSn59qHXstmK2ffpLv2", -"1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", -"ABnLTmg", -"3SEo3LWLoPntC", -"3EFU7m", -"EJDM8drfXA6uyA", -"Rt5zm", -"1111111111" -}; - +// Goal: test low-level base58 encoding functionality BOOST_AUTO_TEST_CASE(base58_EncodeBase58) { - for (unsigned int i=0; i sourcedata = ParseHex(test[0].get_str()); + std::string base58string = test[1].get_str(); + BOOST_CHECK_MESSAGE( + EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string, + strTest); } } +// Goal: test low-level base58 decoding functionality BOOST_AUTO_TEST_CASE(base58_DecodeBase58) { + Array tests = read_json("base58_encode_decode.json"); std::vector result; - for (unsigned int i=0; i expected(vstrIn[i].data, vstrIn[i].data + vstrIn[i].size); - BOOST_CHECK(DecodeBase58(vstrOut[i], result)); - BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 2) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::vector expected = ParseHex(test[0].get_str()); + std::string base58string = test[1].get_str(); + BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest); + BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest); } + BOOST_CHECK(!DecodeBase58("invalid", result)); } +// Visitor to check address type +class TestAddrTypeVisitor : public boost::static_visitor +{ +private: + std::string exp_addrType; +public: + TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { } + bool operator()(const CKeyID &id) const + { + return (exp_addrType == "pubkey"); + } + bool operator()(const CScriptID &id) const + { + return (exp_addrType == "script"); + } + bool operator()(const CNoDestination &no) const + { + return (exp_addrType == "none"); + } +}; + +// Visitor to check address payload +class TestPayloadVisitor : public boost::static_visitor +{ +private: + std::vector exp_payload; +public: + TestPayloadVisitor(std::vector &exp_payload) : exp_payload(exp_payload) { } + bool operator()(const CKeyID &id) const + { + uint160 exp_key(exp_payload); + return exp_key == id; + } + bool operator()(const CScriptID &id) const + { + uint160 exp_key(exp_payload); + return exp_key == id; + } + bool operator()(const CNoDestination &no) const + { + return exp_payload.size() == 0; + } +}; + +// Goal: check that parsed keys match test payload +BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) +{ + Array tests = read_json("base58_keys_valid.json"); + std::vector result; + CBitcoinSecret secret; + CBitcoinAddress addr; + // Save global state + bool fTestNet_stored = fTestNet; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 3) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::string exp_base58string = test[0].get_str(); + std::vector exp_payload = ParseHex(test[1].get_str()); + const Object &metadata = test[2].get_obj(); + bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); + bool isTestnet = find_value(metadata, "isTestnet").get_bool(); + fTestNet = isTestnet; // Override testnet flag + if(isPrivkey) + { + bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + // Must be valid private key + // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! + BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); + BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); + CKey privkey = secret.GetKey(); + BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); + BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); + + // Private key must be invalid public key + addr.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest); + } + else + { + std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey" + // Must be valid public key + BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest); + BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest); + BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest); + CTxDestination dest = addr.Get(); + BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest); + + // Public key must be invalid private key + secret.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); + } + } + // Restore global state + fTestNet = fTestNet_stored; +} + +// Goal: check that generated keys match test vectors +BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) +{ + Array tests = read_json("base58_keys_valid.json"); + std::vector result; + // Save global state + bool fTestNet_stored = fTestNet; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 3) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::string exp_base58string = test[0].get_str(); + std::vector exp_payload = ParseHex(test[1].get_str()); + const Object &metadata = test[2].get_obj(); + bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); + bool isTestnet = find_value(metadata, "isTestnet").get_bool(); + fTestNet = isTestnet; // Override testnet flag + if(isPrivkey) + { + bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + CKey key; + key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); + assert(key.IsValid()); + CBitcoinSecret secret; + secret.SetKey(key); + BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest); + } + else + { + std::string exp_addrType = find_value(metadata, "addrType").get_str(); + CTxDestination dest; + if(exp_addrType == "pubkey") + { + dest = CKeyID(uint160(exp_payload)); + } + else if(exp_addrType == "script") + { + dest = CScriptID(uint160(exp_payload)); + } + else if(exp_addrType == "none") + { + dest = CNoDestination(); + } + else + { + BOOST_ERROR("Bad addrtype: " << strTest); + continue; + } + CBitcoinAddress addrOut; + BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest); + BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); + } + } + + // Visiting a CNoDestination must fail + CBitcoinAddress dummyAddr; + CTxDestination nodest = CNoDestination(); + BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest)); + + // Restore global state + fTestNet = fTestNet_stored; +} + +// Goal: check that base58 parsing code is robust against a variety of corrupted data +BOOST_AUTO_TEST_CASE(base58_keys_invalid) +{ + Array tests = read_json("base58_keys_invalid.json"); // Negative testcases + std::vector result; + CBitcoinSecret secret; + CBitcoinAddress addr; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 1) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::string exp_base58string = test[0].get_str(); + + // must be invalid as public and as private key + addr.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest); + secret.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest); + } +} + + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index 8620f81..196b727 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -12,8 +12,8 @@ BOOST_AUTO_TEST_SUITE(bignum_tests) // You should use it like this: // NOINLINE void function() {...} #if defined(__GNUC__) -// This also works and will be defined for any compiler implementing gcc -// extensions, such as clang and icc. +// This also works and will be defined for any compiler implementing GCC +// extensions, such as Clang and ICC. #define NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) #define NOINLINE __declspec(noinline) @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_SUITE(bignum_tests) // that -ftrapv will detect overflows. NOINLINE void mysetint64(CBigNum& num, int64 n) { - num.setint64(n); + num.setint64(n); } // For each number, we do 2 tests: one with inline code, then we reset the @@ -122,4 +122,57 @@ BOOST_AUTO_TEST_CASE(bignum_setint64) } } + +BOOST_AUTO_TEST_CASE(bignum_SetCompact) +{ + CBigNum num; + num.SetCompact(0); + BOOST_CHECK_EQUAL(num.GetHex(), "0"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + + num.SetCompact(0x00123456); + BOOST_CHECK_EQUAL(num.GetHex(), "0"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + + num.SetCompact(0x01123456); + BOOST_CHECK_EQUAL(num.GetHex(), "12"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); + + // Make sure that we don't generate compacts with the 0x00800000 bit set + num = 0x80; + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); + + num.SetCompact(0x01fedcba); + BOOST_CHECK_EQUAL(num.GetHex(), "-7e"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000U); + + num.SetCompact(0x02123456); + BOOST_CHECK_EQUAL(num.GetHex(), "1234"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); + + num.SetCompact(0x03123456); + BOOST_CHECK_EQUAL(num.GetHex(), "123456"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); + + num.SetCompact(0x04123456); + BOOST_CHECK_EQUAL(num.GetHex(), "12345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); + + num.SetCompact(0x04923456); + BOOST_CHECK_EQUAL(num.GetHex(), "-12345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456U); + + num.SetCompact(0x05009234); + BOOST_CHECK_EQUAL(num.GetHex(), "92340000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); + + num.SetCompact(0x20123456); + BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); + + num.SetCompact(0xff123456); + BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456U); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp new file mode 100644 index 0000000..dc6efff --- /dev/null +++ b/src/test/bloom_tests.cpp @@ -0,0 +1,446 @@ +#include +#include + +#include "bloom.h" +#include "util.h" +#include "key.h" +#include "base58.h" +#include "main.h" + +using namespace std; +using namespace boost::tuples; + +BOOST_AUTO_TEST_SUITE(bloom_tests) + +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!"); + // One bit different in first byte + BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter contains something it shouldn't!"); + + filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "BloomFilter 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)!"); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); + + vector vch = ParseHex("03614e9b050000000000000001"); + vector 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_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) +{ + // Same test as bloom_create_insert_serialize, but we add a nTweak of 100 + CBloomFilter filter(3, 0.01, 2147483649, BLOOM_UPDATE_ALL); + + filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); + BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter 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!"); + + filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "BloomFilter 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)!"); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); + + vector vch = ParseHex("03ce4299050000000100008001"); + vector 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_AUTO_TEST_CASE(bloom_create_insert_key) +{ + string strSecret = string("6v7hgtX6r7frdh7XDRJ3L4JRLMAn9chCgNgSccwqWdp69XfPdX6"); + CBitcoinSecret vchSecret; + BOOST_CHECK(vchSecret.SetString(strSecret)); + + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + vector vchPubKey(pubkey.begin(), pubkey.end()); + + CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); + filter.insert(vchPubKey); + uint160 hash = pubkey.GetID(); + filter.insert(vector(hash.begin(), hash.end())); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); + + vector vch = ParseHex("0322ed23080000000000000001"); + vector 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_AUTO_TEST_CASE(bloom_match) +{ + // Random real transaction (b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b) + CTransaction tx; + CDataStream stream(ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"), SER_DISK, CLIENT_VERSION); + stream >> tx; + + // 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 vch(ch, ch + sizeof(ch) -1); + CDataStream spendStream(vch, SER_DISK, CLIENT_VERSION); + CTransaction spendingTx; + spendStream >> spendingTx; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match tx hash"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // byte-reversed tx hash + filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized tx hash"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input signature"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input pub key"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address"); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx, spendingTx.GetHash()), "Simple Bloom filter didn't add output"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match COutPoint"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); + { + vector data(32 + sizeof(unsigned int)); + memcpy(&data[0], prevOutPoint.hash.begin(), 32); + memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); + filter.insert(data); + } + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized COutPoint"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436")); + BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random tx hash"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431")); + BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random address"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1)); + BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); + BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about"); +} + +BOOST_AUTO_TEST_CASE(merkle_block_1) +{ + // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) + // With 9 txes + CBlock block; + CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the last transaction + filter.insert(uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); + + vector vMatched; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Also match the 8th transaction + filter.insert(uint256("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_2) +{ + // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) + // With 4 txes + CBlock block; + CDataStream stream(ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the first transaction + filter.insert(uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); + + vector vMatched; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) + // This should match the third transaction because it spends the output matched + // It also matches the fourth transaction, which spends to the pubkey again + filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af")); + + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 4); + + BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")); + BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); + + BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2")); + BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 2); + + BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); + BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) +{ + // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) + // With 4 txes + CBlock block; + CDataStream stream(ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); + // Match the first transaction + filter.insert(uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); + + vector vMatched; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) + // This should not match the third transaction though it spends the output matched + // It will match the fourth transaction, which has another pay-to-pubkey output to the same address + filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af")); + + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 3); + + BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")); + BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); + + BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); + BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) +{ + // Random real block (000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45) + // With one tx + CBlock block; + CDataStream stream(ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the only transaction + filter.insert(uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); + + vector vMatched; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION); + merkleStream << merkleBlock; + + vector vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); + vector expected(vch.size()); + + for (unsigned int i = 0; i < vch.size(); i++) + expected[i] = (char)vch[i]; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), merkleStream.begin(), merkleStream.end()); +} + +BOOST_AUTO_TEST_CASE(merkle_block_4) +{ + // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) + // With 7 txes + CBlock block; + CDataStream stream(ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the last transaction + filter.insert(uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); + + vector vMatched; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Also match the 4th transaction + filter.insert(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 3); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only) +{ + // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) + // With 7 txes + CBlock block; + CDataStream stream(ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_P2PUBKEY_ONLY); + // Match the generation pubkey + filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91")); + // ...and the output address of the 4th transaction + filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + // We should match the generation outpoint + BOOST_CHECK(filter.contains(COutPoint(uint256("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0))); + // ... but not the 4th transaction's output (its not pay-2-pubkey) + BOOST_CHECK(!filter.contains(COutPoint(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); +} + +BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) +{ + // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) + // With 7 txes + CBlock block; + CDataStream stream(ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); + // Match the generation pubkey + filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91")); + // ...and the output address of the 4th transaction + filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + // We shouldn't match any outpoints (UPDATE_NONE) + BOOST_CHECK(!filter.contains(COutPoint(uint256("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0))); + BOOST_CHECK(!filter.contains(COutPoint(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp new file mode 100644 index 0000000..42d21f8 --- /dev/null +++ b/src/test/canonical_tests.cpp @@ -0,0 +1,87 @@ +// +// Unit tests for canonical signatures + +#include "json/json_spirit_writer_template.h" +#include +#include + +#include "key.h" +#include "script.h" +#include "util.h" + +using namespace std; +using namespace json_spirit; + + +// In script_tests.cpp +extern Array read_json(const std::string& filename); + +BOOST_AUTO_TEST_SUITE(canonical_tests) + +// OpenSSL-based test for canonical signature (without test for hashtype byte) +bool static IsCanonicalSignature_OpenSSL_inner(const std::vector& vchSig) +{ + if (vchSig.size() == 0) + return false; + const unsigned char *input = &vchSig[0]; + ECDSA_SIG *psig = NULL; + d2i_ECDSA_SIG(&psig, &input, vchSig.size()); + if (psig == NULL) + return false; + unsigned char buf[256]; + unsigned char *pbuf = buf; + unsigned int nLen = i2d_ECDSA_SIG(psig, NULL); + if (nLen != vchSig.size()) { + ECDSA_SIG_free(psig); + return false; + } + nLen = i2d_ECDSA_SIG(psig, &pbuf); + ECDSA_SIG_free(psig); + return (memcmp(&vchSig[0], &buf[0], nLen) == 0); +} + +// OpenSSL-based test for canonical signature +bool static IsCanonicalSignature_OpenSSL(const std::vector &vchSignature) { + if (vchSignature.size() < 1) + return false; + if (vchSignature.size() > 127) + return false; + if (vchSignature[vchSignature.size() - 1] & 0x7C) + return false; + + std::vector vchSig(vchSignature); + vchSig.pop_back(); + if (!IsCanonicalSignature_OpenSSL_inner(vchSig)) + return false; + return true; +} + +BOOST_AUTO_TEST_CASE(script_canon) +{ + Array tests = read_json("sig_canonical.json"); + + BOOST_FOREACH(Value &tv, tests) { + string test = tv.get_str(); + if (IsHex(test)) { + std::vector sig = ParseHex(test); + BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig), test); + BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test); + } + } +} + +BOOST_AUTO_TEST_CASE(script_noncanon) +{ + Array tests = read_json("sig_noncanonical.json"); + + BOOST_FOREACH(Value &tv, tests) { + string test = tv.get_str(); + if (IsHex(test)) { + std::vector sig = ParseHex(test); + BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig), test); + BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp new file mode 100644 index 0000000..3cfb6db --- /dev/null +++ b/src/test/checkblock_tests.cpp @@ -0,0 +1,66 @@ +// +// Unit tests for block.CheckBlock() +// +#include + +#include // for 'map_list_of()' +#include +#include +#include + +#include "main.h" +#include "wallet.h" +#include "net.h" +#include "util.h" + +BOOST_AUTO_TEST_SUITE(CheckBlock_tests) + +bool +read_block(const std::string& filename, CBlock& block) +{ + namespace fs = boost::filesystem; + fs::path testFile = fs::current_path() / "test" / "data" / filename; +#ifdef TEST_DATA_DIR + if (!fs::exists(testFile)) + { + testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; + } +#endif + FILE* fp = fopen(testFile.string().c_str(), "rb"); + if (!fp) return false; + + fseek(fp, 8, SEEK_SET); // skip msgheader/size + + CAutoFile filein = CAutoFile(fp, SER_DISK, CLIENT_VERSION); + if (!filein) return false; + + filein >> block; + + return true; +} + +BOOST_AUTO_TEST_CASE(May15) +{ + // Putting a 1MB binary file in the git repository is not a great + // idea, so this test is only run if you manually download + // test/data/Mar12Fork.dat from + // http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/Mar12Fork.dat/download + unsigned int tMay15 = 1368576000; + SetMockTime(tMay15); // Test as if it was right at May 15 + + CBlock forkingBlock; + if (read_block("Mar12Fork.dat", forkingBlock)) + { + CValidationState state; + forkingBlock.nTime = tMay15-1; // Invalidates PoW + BOOST_CHECK(!forkingBlock.CheckBlock(state, false, false)); + + // After May 15'th, big blocks are OK: + forkingBlock.nTime = tMay15; // Invalidates PoW + BOOST_CHECK(forkingBlock.CheckBlock(state, false, false)); + } + + SetMockTime(0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp new file mode 100644 index 0000000..71b86bc --- /dev/null +++ b/src/test/compress_tests.cpp @@ -0,0 +1,62 @@ +#include + +#include +#include + +#include "main.h" + +// amounts 0.00000001 .. 0.00100000 +#define NUM_MULTIPLES_UNIT 100000 + +// amounts 0.01 .. 100.00 +#define NUM_MULTIPLES_CENT 10000 + +// amounts 1 .. 10000 +#define NUM_MULTIPLES_1BTC 10000 + +// amounts 50 .. 21000000 +#define NUM_MULTIPLES_50BTC 420000 + +using namespace std; + +BOOST_AUTO_TEST_SUITE(compress_tests) + +bool static TestEncode(uint64 in) { + return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in)); +} + +bool static TestDecode(uint64 in) { + return in == CTxOutCompressor::CompressAmount(CTxOutCompressor::DecompressAmount(in)); +} + +bool static TestPair(uint64 dec, uint64 enc) { + return CTxOutCompressor::CompressAmount(dec) == enc && + CTxOutCompressor::DecompressAmount(enc) == dec; +} + +BOOST_AUTO_TEST_CASE(compress_amounts) +{ + BOOST_CHECK(TestPair( 0, 0x0)); + BOOST_CHECK(TestPair( 1, 0x1)); + BOOST_CHECK(TestPair( CENT, 0x7)); + BOOST_CHECK(TestPair( COIN, 0x9)); + BOOST_CHECK(TestPair( 50*COIN, 0x32)); + BOOST_CHECK(TestPair(21000000*COIN, 0x1406f40)); + + for (uint64 i = 1; i <= NUM_MULTIPLES_UNIT; i++) + BOOST_CHECK(TestEncode(i)); + + for (uint64 i = 1; i <= NUM_MULTIPLES_CENT; i++) + BOOST_CHECK(TestEncode(i * CENT)); + + for (uint64 i = 1; i <= NUM_MULTIPLES_1BTC; i++) + BOOST_CHECK(TestEncode(i * COIN)); + + for (uint64 i = 1; i <= NUM_MULTIPLES_50BTC; i++) + BOOST_CHECK(TestEncode(i * 50 * COIN)); + + for (uint64 i = 0; i < 100000; i++) + BOOST_CHECK(TestDecode(i)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/data/alertTests b/src/test/data/alertTests new file mode 100644 index 0000000000000000000000000000000000000000..24e906c1a5711039a41c93ad4be2a51228be7684 GIT binary patch literal 1284 zcmZ={WME*h0b&qn2n6vM7$78=$-q!32;_o9cpY<6i%Jxd^K)}k^GetuJVORI0~aO* z)z8h|eCu0Ht*g7;lqzzs80#oG3og8Dl-Tw*`buZZb|!_g#Zi0m{AP6o-H}nAW!-2l zBjmtt;;kxsrh?(8Le1f?$sj8TI)ss5KRB@@zc?e)%0SOh&p;p3VUkdXDWv5WDL@q~ zfE6>i8@MtlGE8~OxK)M!{0(C&uZ~ShX>z9pSyOsUCpz}QEl0~<<7(^qTI@a?p9>J5mvV=;B>nV&R-H zJrr!xY~H&zr#X?aA}Eg915J(06gWze;Y-8Qtod_(+bm3UTirh|_;2RFh5L0x z9BXP%#JsiJ&r`yrpg3XmT7%0j?#0YDe0(m}9VWlrR1*wN>TlRQdBM|e{#jTZ#R78_ zH;^F)#0PN*8gibVX}E{dELf?6Oxgm4;E6a=#Ik3E|`vlW)~wY*#(l; zwy|YK{D|NBN;7ityU907ZpzJ>wrFnS+$m8Z?jPRq`SJpz^+O(KvUKU9w!g*+XScjQ z&{k`&P+D{Khr*sq39_$6PBVvLb1WOov7o@ScjCtuf-D09pOl%WpHpnD zkeZy4ub>Xi&gTsbFFy|S&f4>3pU_nnry}i^?aMwm__uR9NOK7QsqSRi}v`XKR5Z3i=d=suR3lEY9M_X7Ye3x~P@ literal 0 HcmV?d00001 diff --git a/src/test/data/base58_encode_decode.json b/src/test/data/base58_encode_decode.json new file mode 100644 index 0000000..9448f25 --- /dev/null +++ b/src/test/data/base58_encode_decode.json @@ -0,0 +1,14 @@ +[ +["", ""], +["61", "2g"], +["626262", "a3gV"], +["636363", "aPEr"], +["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"], +["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"], +["516b6fcd0f", "ABnLTmg"], +["bf4f89001e670274dd", "3SEo3LWLoPntC"], +["572e4794", "3EFU7m"], +["ecac89cad93923c02321", "EJDM8drfXA6uyA"], +["10c8511e", "Rt5zm"], +["00000000000000000000", "1111111111"] +] diff --git a/src/test/data/base58_keys_invalid.json b/src/test/data/base58_keys_invalid.json new file mode 100644 index 0000000..a088620 --- /dev/null +++ b/src/test/data/base58_keys_invalid.json @@ -0,0 +1,152 @@ +[ + [ + "" + ], + [ + "x" + ], + [ + "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y" + ], + [ + "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv" + ], + [ + "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S" + ], + [ + "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf" + ], + [ + "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq" + ], + [ + "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb" + ], + [ + "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs" + ], + [ + "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3" + ], + [ + "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th" + ], + [ + "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va" + ], + [ + "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk" + ], + [ + "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs" + ], + [ + "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo" + ], + [ + "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso" + ], + [ + "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq" + ], + [ + "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN" + ], + [ + "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i" + ], + [ + "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos" + ], + [ + "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu" + ], + [ + "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb" + ], + [ + "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ" + ], + [ + "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ" + ], + [ + "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu" + ], + [ + "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU" + ], + [ + "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs" + ], + [ + "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn" + ], + [ + "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj" + ], + [ + "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny" + ], + [ + "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc" + ], + [ + "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ" + ], + [ + "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP" + ], + [ + "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw" + ], + [ + "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX" + ], + [ + "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB" + ], + [ + "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ" + ], + [ + "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs" + ], + [ + "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ" + ], + [ + "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4" + ], + [ + "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK" + ], + [ + "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig" + ], + [ + "EsYbG4tWWWY45G31nox838qNdzksbPySWc" + ], + [ + "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT" + ], + [ + "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx" + ], + [ + "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde" + ], + [ + "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU" + ], + [ + "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf" + ], + [ + "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd" + ], + [ + "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED" + ] +] diff --git a/src/test/data/base58_keys_valid.json b/src/test/data/base58_keys_valid.json new file mode 100644 index 0000000..9409afc --- /dev/null +++ b/src/test/data/base58_keys_valid.json @@ -0,0 +1,452 @@ +[ + [ + "Lf8Th7S4LDxFUZegQgn5z5se7BahrJ9DeV", + "da589613a4c031bafa9fa5490fdaea491e81e687", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", + "74f209f6ea907e2ea48f74fae05782ae8a665257", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "53c0307d6851aa0ce7825ba883c6bd9ad242b486", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", + "6349a418fc4578d10a372b54b45c280cc8c4382f", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "6uoCwsNo3oV9rsYwHY7TeGtZpwLbWJyVcKCAQyz91Ah4XbZYxw3", + "58fb1bfc04bd9293a916d0688cba48ac143921a400e2086f43e16a02e572f2de", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "T9wxCLuZLZ2uSs44HUzGW5ZC2hNtnZqsbZGKtWC1MhJjHbRNCVYP", + "cdc32fb8fab8b80ecf7e7501d93173f4c10bc45bd42c030ceaa7d947090bb441", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "LP7Ls95NmnuWi5o9bKZrezLiyCPy1B5P1q", + "2aa075715a16b3f8fe726ae9c5c4aa044bbca054", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", + "fcc5460dd6e2487c7d75b1963625da0e8f4c5975", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", + "f1d470f9b02370fdec2e6b708b08ac431bf7a5f7", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", + "c579342c2c4c9220205e2cdc285617040c924a0a", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "6vs3xk3YxdBcHAA12Y63qwALButouE5SBzZUnBzCq5N8wvMjnZ9", + "e5686121b71c57364887d32d7b90885af98ebd96972bd1c00a6bd2a8f1f35b45", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "T4rLdfaJrCLN3uemQQoi1nAhXSAFwepDX4Ahjw8EjVP27Avmjzo4", + "35b0165377348a7ba55184f5a30834e7b5ba20dcb3ed4c7bb330e1dc631b050f", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", + "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", + "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "LdaHb6WXgyf38F96JweN9XNWKJS91iCLNF", + "c94ab72be12aa1a05f1af875f7250333e5d27aa2", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", + "63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", + "ef66444b5b17f14e8fae6e7e19b045a78c54fd79", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", + "c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "6uQT9bdxJhE83M8RjCQfo7U9oaAo5ncAP5skuzemx5DeuA6hB9o", + "2550053cc3dfc32104fd3d0b1bce0e6f6e65a0564d36018f1544d9aa4764ad39", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "T4cpoFeaPJhTCTdLfmbNmA2f2PyjJgpCWU2pcdzBwExj5F9panJ4", + "2ebc4b6d730064cf6023b006f2b4aff89a53ac04740f21d84efa6ef33d8855cd", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", + "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", + "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "LX5YLxmAJ3YKHaRc2eR2A2s1cnw6fPA4SE", + "820a3743686bf0fd46005de06cfd382bbcbd70c5", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", + "188f91a931947eddd7432d6e614387e32b244709", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", + "1694f5bc1a7295b600f40018a618a6ea48eeb498", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", + "3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "6usgadpSJcXjfNFqn2Cz1kgKEWYhtzANKvhBs5pAKpsoCCRRv6H", + "63252cd47897bd0380152475453e275cf504226ee82253bbc980a926b2a71689", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "T8wbMCiccPDTa3hUFT23LUXeWU1AiNpVy8MgsQMFAbPjDjpWPVod", + "afbd7a0468460c25eef3576503578ce5ff985a598e30960018ad559282b3ef3c", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", + "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "LZa2tVcdFafKLMVeEKijaJ45jvruvZSRFK", + "9d5df1006a8a175f342dd0610337331fceb45830", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", + "f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", + "261f83568a098a8638844bd7aeca039d5f2352c0", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", + "e930e1834a4d234702773951d627cce82fbb5d2e", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "6vUB9QijBguaXPMoLXK5ZwLJCZTjKKAeQxgWfZLfJvForhka5D8", + "b176f3e34ff474dea2fb3cafb19be519e6e8f34fd39166f5d5ce657154eb05d6", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "T5MCn7wUVMmffkTpoRNdW1MhWaRoSgNESC5tzeTSHie92tMBxjEZ", + "448970a2a25f412fd9fc48d9df5dee7a01ad039b824efc28663f31728b92cce2", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", + "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", + "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "LPJfbhKmpiDNczUF1xwL8mBpwjg22kCRiw", + "2cc4ac26bb08dfad7a40aa48b88046cfd2c930fd", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", + "3f210e7277c899c3a155cc1c90f4106cbddeec6e", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", + "c8a3c2a09a298592c3e180f02487cd91ba3400b5", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", + "99b31df7c9068d1481b596578ddbb4d3bd90baeb", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "6vM32FdMdhMF7qS9TLDH2sTLC6wALamAk9ebRFESaUpq9yf2mbE", + "a1409598b6d7490548b3d5f3255b2c6adf487d82306a920d41362b98350b18a1", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "TA8YZ69RUn4NjmCJ9gaoDmxesD9bb9xzkXKHDcymJApWVKTPbYTm", + "d3362922cebe534a1cef42928fc7208c9cfa1c4413422b2af741110fe5b0c8de", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", + "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", + "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "LWzPZSe3opyEdEmRAiULVLR3zBZS3oY9Wu", + "8110cd88bfb26bfb08e0878ddb34af03fc03c8b7", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + "5ece0cadddc415b1980f001785947120acdb36fc", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ] +] diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 0c2d711..9566422 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -39,6 +39,9 @@ ["1", "RETURN"], ["1", "DUP IF RETURN ENDIF"], +["1", "RETURN 'data'", "canonical prunable txout format"], +["0 IF", "RETURN ENDIF 1", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], + ["0", "VERIFY 1"], ["1", "VERIFY"], ["1", "VERIFY 0"], @@ -128,13 +131,79 @@ ["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL"], ["0x50","1", "opcode 0x50 is reserved"], -["1", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid"], +["1", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"], +["1", "IF 0xbb ELSE 1 ENDIF"], +["1", "IF 0xbc ELSE 1 ENDIF"], +["1", "IF 0xbd ELSE 1 ENDIF"], +["1", "IF 0xbe ELSE 1 ENDIF"], +["1", "IF 0xbf ELSE 1 ENDIF"], ["1", "IF 0xc0 ELSE 1 ENDIF"], +["1", "IF 0xc1 ELSE 1 ENDIF"], +["1", "IF 0xc2 ELSE 1 ENDIF"], +["1", "IF 0xc3 ELSE 1 ENDIF"], +["1", "IF 0xc4 ELSE 1 ENDIF"], +["1", "IF 0xc5 ELSE 1 ENDIF"], +["1", "IF 0xc6 ELSE 1 ENDIF"], +["1", "IF 0xc7 ELSE 1 ENDIF"], +["1", "IF 0xc8 ELSE 1 ENDIF"], +["1", "IF 0xc9 ELSE 1 ENDIF"], +["1", "IF 0xca ELSE 1 ENDIF"], +["1", "IF 0xcb ELSE 1 ENDIF"], +["1", "IF 0xcc ELSE 1 ENDIF"], +["1", "IF 0xcd ELSE 1 ENDIF"], +["1", "IF 0xce ELSE 1 ENDIF"], +["1", "IF 0xcf ELSE 1 ENDIF"], +["1", "IF 0xd0 ELSE 1 ENDIF"], ["1", "IF 0xd1 ELSE 1 ENDIF"], +["1", "IF 0xd2 ELSE 1 ENDIF"], +["1", "IF 0xd3 ELSE 1 ENDIF"], +["1", "IF 0xd4 ELSE 1 ENDIF"], +["1", "IF 0xd5 ELSE 1 ENDIF"], +["1", "IF 0xd6 ELSE 1 ENDIF"], +["1", "IF 0xd7 ELSE 1 ENDIF"], +["1", "IF 0xd8 ELSE 1 ENDIF"], +["1", "IF 0xd9 ELSE 1 ENDIF"], +["1", "IF 0xda ELSE 1 ENDIF"], +["1", "IF 0xdb ELSE 1 ENDIF"], +["1", "IF 0xdc ELSE 1 ENDIF"], +["1", "IF 0xdd ELSE 1 ENDIF"], +["1", "IF 0xde ELSE 1 ENDIF"], +["1", "IF 0xdf ELSE 1 ENDIF"], +["1", "IF 0xe0 ELSE 1 ENDIF"], +["1", "IF 0xe1 ELSE 1 ENDIF"], +["1", "IF 0xe2 ELSE 1 ENDIF"], +["1", "IF 0xe3 ELSE 1 ENDIF"], +["1", "IF 0xe4 ELSE 1 ENDIF"], +["1", "IF 0xe5 ELSE 1 ENDIF"], +["1", "IF 0xe6 ELSE 1 ENDIF"], +["1", "IF 0xe7 ELSE 1 ENDIF"], +["1", "IF 0xe8 ELSE 1 ENDIF"], +["1", "IF 0xe9 ELSE 1 ENDIF"], +["1", "IF 0xea ELSE 1 ENDIF"], +["1", "IF 0xeb ELSE 1 ENDIF"], +["1", "IF 0xec ELSE 1 ENDIF"], +["1", "IF 0xed ELSE 1 ENDIF"], ["1", "IF 0xee ELSE 1 ENDIF"], +["1", "IF 0xef ELSE 1 ENDIF"], +["1", "IF 0xf0 ELSE 1 ENDIF"], +["1", "IF 0xf1 ELSE 1 ENDIF"], +["1", "IF 0xf2 ELSE 1 ENDIF"], +["1", "IF 0xf3 ELSE 1 ENDIF"], +["1", "IF 0xf4 ELSE 1 ENDIF"], +["1", "IF 0xf5 ELSE 1 ENDIF"], +["1", "IF 0xf6 ELSE 1 ENDIF"], +["1", "IF 0xf7 ELSE 1 ENDIF"], +["1", "IF 0xf8 ELSE 1 ENDIF"], +["1", "IF 0xf9 ELSE 1 ENDIF"], +["1", "IF 0xfa ELSE 1 ENDIF"], +["1", "IF 0xfb ELSE 1 ENDIF"], +["1", "IF 0xfc ELSE 1 ENDIF"], ["1", "IF 0xfd ELSE 1 ENDIF"], +["1", "IF 0xfe ELSE 1 ENDIF"], ["1", "IF 0xff ELSE 1 ENDIF"], +["1 IF 1 ELSE", "0xff ENDIF", "invalid because scriptSig and scriptPubKey are processed separately"], + ["NOP", "RIPEMD160"], ["NOP", "SHA1"], ["NOP", "SHA256"], @@ -144,9 +213,15 @@ ["NOP", "'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", ">520 byte push"], +["0", +"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", +">520 byte push in non-executed IF branch"], ["1", "0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", ">201 opcodes executed. 0x61 is NOP"], +["0", +"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", +">201 opcodes including non-executed IF branch. 0x61 is NOP"], ["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", "1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", ">1,000 stack size (0x6f is 3DUP)"], @@ -157,5 +232,83 @@ "0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", "10,001-byte scriptPubKey"], -["NOP1","NOP10"] +["NOP1","NOP10"], + +["1","VER", "OP_VER is reserved"], +["1","VERIF", "OP_VERIF is reserved"], +["1","VERNOTIF", "OP_VERNOTIF is reserved"], +["1","RESERVED1", "OP_RESERVED1 is reserved"], +["1","RESERVED2", "OP_RESERVED2 is reserved"], +["1","0xba", "0xba == OP_NOP10 + 1"], + +["2147483648", "1ADD 1", "We cannot do math on 5-byte integers"], +["-2147483648", "1ADD 1", "Because we use a sign bit, -2147483648 is also 5 bytes"], + +["1", "1 ENDIF", "ENDIF without IF"], +["1", "IF 1", "IF without ENDIF"], +["1 IF 1", "ENDIF", "IFs don't carry over"], + +["NOP", "IF 1 ENDIF", "The following tests check the if(stack.size() < N) tests in each opcode"], +["NOP", "NOTIF 1 ENDIF", "They are here to catch copy-and-paste errors"], +["NOP", "VERIFY 1", "Most of them are duplicated elsewhere,"], + +["NOP", "TOALTSTACK 1", "but, hey, more is always better, right?"], +["1", "FROMALTSTACK"], +["1", "2DROP 1"], +["1", "2DUP"], +["1 1", "3DUP"], +["1 1 1", "2OVER"], +["1 1 1 1 1", "2ROT"], +["1 1 1", "2SWAP"], +["NOP", "IFDUP 1"], +["NOP", "DROP 1"], +["NOP", "DUP 1"], +["1", "NIP"], +["1", "OVER"], +["1 1 1 3", "PICK"], +["0", "PICK 1"], +["1 1 1 3", "ROLL"], +["0", "ROLL 1"], +["1 1", "ROT"], +["1", "SWAP"], +["1", "TUCK"], + +["NOP", "SIZE 1"], + +["1", "EQUAL 1"], +["1", "EQUALVERIFY 1"], + +["NOP", "1ADD 1"], +["NOP", "1SUB 1"], +["NOP", "NEGATE 1"], +["NOP", "ABS 1"], +["NOP", "NOT 1"], +["NOP", "0NOTEQUAL 1"], + +["1", "ADD"], +["1", "SUB"], +["1", "BOOLAND"], +["1", "BOOLOR"], +["1", "NUMEQUAL"], +["1", "NUMEQUALVERIFY 1"], +["1", "NUMNOTEQUAL"], +["1", "LESSTHAN"], +["1", "GREATERTHAN"], +["1", "LESSTHANOREQUAL"], +["1", "GREATERTHANOREQUAL"], +["1", "MIN"], +["1", "MAX"], +["1 1", "WITHIN"], + +["NOP", "RIPEMD160 1"], +["NOP", "SHA1 1"], +["NOP", "SHA256 1"], +["NOP", "HASH160 1"], +["NOP", "HASH256 1"], + +["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Tests for Script.IsPushOnly()"], +["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"], + +["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "OP_RESERVED in P2SH should fail"], +["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "OP_VER in P2SH should fail"] ] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index 6ef4d46..58682d3 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -34,6 +34,8 @@ ["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], ["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], +["0", "IF RETURN ENDIF 1", "RETURN only works if executed"], + ["1 1", "VERIFY"], ["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL"], @@ -52,8 +54,18 @@ ["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"], ["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"], ["22 21 20", "ROT 22 EQUAL"], +["22 21 20", "ROT DROP 20 EQUAL"], +["22 21 20", "ROT DROP DROP 21 EQUAL"], ["22 21 20", "ROT ROT 21 EQUAL"], ["22 21 20", "ROT ROT ROT 20 EQUAL"], +["25 24 23 22 21 20", "2ROT 24 EQUAL"], +["25 24 23 22 21 20", "2ROT DROP 25 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL"], +["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL"], +["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL"], ["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL"], ["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"], ["13 14", "2DUP ROT EQUALVERIFY EQUAL"], @@ -178,10 +190,74 @@ ["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL"], ["0", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"], +["0", "IF 0xbb ELSE 1 ENDIF"], +["0", "IF 0xbc ELSE 1 ENDIF"], +["0", "IF 0xbd ELSE 1 ENDIF"], +["0", "IF 0xbe ELSE 1 ENDIF"], +["0", "IF 0xbf ELSE 1 ENDIF"], ["0", "IF 0xc0 ELSE 1 ENDIF"], +["0", "IF 0xc1 ELSE 1 ENDIF"], +["0", "IF 0xc2 ELSE 1 ENDIF"], +["0", "IF 0xc3 ELSE 1 ENDIF"], +["0", "IF 0xc4 ELSE 1 ENDIF"], +["0", "IF 0xc5 ELSE 1 ENDIF"], +["0", "IF 0xc6 ELSE 1 ENDIF"], +["0", "IF 0xc7 ELSE 1 ENDIF"], +["0", "IF 0xc8 ELSE 1 ENDIF"], +["0", "IF 0xc9 ELSE 1 ENDIF"], +["0", "IF 0xca ELSE 1 ENDIF"], +["0", "IF 0xcb ELSE 1 ENDIF"], +["0", "IF 0xcc ELSE 1 ENDIF"], +["0", "IF 0xcd ELSE 1 ENDIF"], +["0", "IF 0xce ELSE 1 ENDIF"], +["0", "IF 0xcf ELSE 1 ENDIF"], +["0", "IF 0xd0 ELSE 1 ENDIF"], ["0", "IF 0xd1 ELSE 1 ENDIF"], +["0", "IF 0xd2 ELSE 1 ENDIF"], +["0", "IF 0xd3 ELSE 1 ENDIF"], +["0", "IF 0xd4 ELSE 1 ENDIF"], +["0", "IF 0xd5 ELSE 1 ENDIF"], +["0", "IF 0xd6 ELSE 1 ENDIF"], +["0", "IF 0xd7 ELSE 1 ENDIF"], +["0", "IF 0xd8 ELSE 1 ENDIF"], +["0", "IF 0xd9 ELSE 1 ENDIF"], +["0", "IF 0xda ELSE 1 ENDIF"], +["0", "IF 0xdb ELSE 1 ENDIF"], +["0", "IF 0xdc ELSE 1 ENDIF"], +["0", "IF 0xdd ELSE 1 ENDIF"], +["0", "IF 0xde ELSE 1 ENDIF"], +["0", "IF 0xdf ELSE 1 ENDIF"], +["0", "IF 0xe0 ELSE 1 ENDIF"], +["0", "IF 0xe1 ELSE 1 ENDIF"], +["0", "IF 0xe2 ELSE 1 ENDIF"], +["0", "IF 0xe3 ELSE 1 ENDIF"], +["0", "IF 0xe4 ELSE 1 ENDIF"], +["0", "IF 0xe5 ELSE 1 ENDIF"], +["0", "IF 0xe6 ELSE 1 ENDIF"], +["0", "IF 0xe7 ELSE 1 ENDIF"], +["0", "IF 0xe8 ELSE 1 ENDIF"], +["0", "IF 0xe9 ELSE 1 ENDIF"], +["0", "IF 0xea ELSE 1 ENDIF"], +["0", "IF 0xeb ELSE 1 ENDIF"], +["0", "IF 0xec ELSE 1 ENDIF"], +["0", "IF 0xed ELSE 1 ENDIF"], ["0", "IF 0xee ELSE 1 ENDIF"], +["0", "IF 0xef ELSE 1 ENDIF"], +["0", "IF 0xf0 ELSE 1 ENDIF"], +["0", "IF 0xf1 ELSE 1 ENDIF"], +["0", "IF 0xf2 ELSE 1 ENDIF"], +["0", "IF 0xf3 ELSE 1 ENDIF"], +["0", "IF 0xf4 ELSE 1 ENDIF"], +["0", "IF 0xf5 ELSE 1 ENDIF"], +["0", "IF 0xf6 ELSE 1 ENDIF"], +["0", "IF 0xf7 ELSE 1 ENDIF"], +["0", "IF 0xf8 ELSE 1 ENDIF"], +["0", "IF 0xf9 ELSE 1 ENDIF"], +["0", "IF 0xfa ELSE 1 ENDIF"], +["0", "IF 0xfb ELSE 1 ENDIF"], +["0", "IF 0xfc ELSE 1 ENDIF"], ["0", "IF 0xfd ELSE 1 ENDIF"], +["0", "IF 0xfe ELSE 1 ENDIF"], ["0", "IF 0xff ELSE 1 ENDIF"], ["NOP", @@ -200,5 +276,104 @@ "'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", "Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], -["NOP","1"] +["NOP","1"], + +["1", "0x01 0x01 EQUAL", "The following is useful for checking implementations of BN_bn2mpi"], +["127", "0x01 0x7F EQUAL"], +["128", "0x02 0x8000 EQUAL", "Leave room for the sign bit"], +["32767", "0x02 0xFF7F EQUAL"], +["32768", "0x03 0x008000 EQUAL"], +["8388607", "0x03 0xFFFF7F EQUAL"], +["8388608", "0x04 0x00008000 EQUAL"], +["2147483647", "0x04 0xFFFFFF7F EQUAL"], +["2147483648", "0x05 0x0000008000 EQUAL"], +["-1", "0x01 0x81 EQUAL", "Numbers are little-endian with the MSB being a sign bit"], +["-127", "0x01 0xFF EQUAL"], +["-128", "0x02 0x8080 EQUAL"], +["-32767", "0x02 0xFFFF EQUAL"], +["-32768", "0x03 0x008080 EQUAL"], +["-8388607", "0x03 0xFFFFFF EQUAL"], +["-8388608", "0x04 0x00008080 EQUAL"], +["-2147483647", "0x04 0xFFFFFFFF EQUAL"], +["-2147483648", "0x05 0x0000008080 EQUAL"], + +["2147483647", "1ADD 2147483648 EQUAL", "We can do math on 4-byte integers, and compare 5-byte ones"], +["2147483647", "1ADD 1"], +["-2147483647", "1ADD 1"], + + +["NOP", "NOP 1", "The following tests check the if(stack.size() < N) tests in each opcode"], +["1", "IF 1 ENDIF", "They are here to catch copy-and-paste errors"], +["0", "NOTIF 1 ENDIF", "Most of them are duplicated elsewhere,"], +["1", "VERIFY 1", "but, hey, more is always better, right?"], + +["0", "TOALTSTACK 1"], +["1", "TOALTSTACK FROMALTSTACK"], +["0 0", "2DROP 1"], +["0 1", "2DUP"], +["0 0 1", "3DUP"], +["0 1 0 0", "2OVER"], +["0 1 0 0 0 0", "2ROT"], +["0 1 0 0", "2SWAP"], +["1", "IFDUP"], +["NOP", "DEPTH 1"], +["0", "DROP 1"], +["1", "DUP"], +["0 1", "NIP"], +["1 0", "OVER"], +["1 0 0 0 3", "PICK"], +["1 0", "PICK"], +["1 0 0 0 3", "ROLL"], +["1 0", "ROLL"], +["1 0 0", "ROT"], +["1 0", "SWAP"], +["0 1", "TUCK"], + +["1", "SIZE"], + +["0 0", "EQUAL"], +["0 0", "EQUALVERIFY 1"], + +["0", "1ADD"], +["2", "1SUB"], +["-1", "NEGATE"], +["-1", "ABS"], +["0", "NOT"], +["-1", "0NOTEQUAL"], + +["1 0", "ADD"], +["1 0", "SUB"], +["-1 -1", "BOOLAND"], +["-1 0", "BOOLOR"], +["0 0", "NUMEQUAL"], +["0 0", "NUMEQUALVERIFY 1"], +["-1 0", "NUMNOTEQUAL"], +["-1 0", "LESSTHAN"], +["1 0", "GREATERTHAN"], +["0 0", "LESSTHANOREQUAL"], +["0 0", "GREATERTHANOREQUAL"], +["-1 0", "MIN"], +["1 0", "MAX"], +["-1 -1 0", "WITHIN"], + +["0", "RIPEMD160"], +["0", "SHA1"], +["0", "SHA256"], +["0", "HASH160"], +["0", "HASH256"], +["NOP", "CODESEPARATOR 1"], + +["NOP", "NOP1 1"], +["NOP", "NOP2 1"], +["NOP", "NOP3 1"], +["NOP", "NOP4 1"], +["NOP", "NOP5 1"], +["NOP", "NOP6 1"], +["NOP", "NOP7 1"], +["NOP", "NOP8 1"], +["NOP", "NOP9 1"], +["NOP", "NOP10 1"], + +["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Very basic P2SH"], +["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"] ] diff --git a/src/test/data/sig_canonical.json b/src/test/data/sig_canonical.json new file mode 100644 index 0000000..e43a086 --- /dev/null +++ b/src/test/data/sig_canonical.json @@ -0,0 +1,7 @@ +[ + "300602010002010001", + "3008020200ff020200ff01", + "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001", + "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01", + "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01" +] diff --git a/src/test/data/sig_noncanonical.json b/src/test/data/sig_noncanonical.json new file mode 100644 index 0000000..d9a6c1c --- /dev/null +++ b/src/test/data/sig_noncanonical.json @@ -0,0 +1,22 @@ +[ + "non-hex strings are ignored", + + "too short:", "30050201FF020001", + "too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11", + "type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101", + "R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001", + + "R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + + + "S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001", + "S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", + "S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01" +] diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json new file mode 100644 index 0000000..81e77b7 --- /dev/null +++ b/src/test/data/tx_invalid.json @@ -0,0 +1,69 @@ +[ +["The following are deserialized transactions which are invalid."], +["They are in the form"], +["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], +["serializedTransaction, enforceP2SH]"], +["Objects that are only a single string (like this one) are ignored"], + +["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"], +[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]], +"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", true], + +["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], +["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"], +["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["An invalid P2SH Transaction"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true], + +["Tests for CTransaction::CheckTransaction()"], +["No inputs"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], +"0100000000010000000000000000015100000000", true], + +["No outputs"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", true], + +["Negative output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", true], + +["MAX_MONEY + 1 output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", true], + +["MAX_MONEY output + 1 output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", true], + +["Duplicate inputs"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]], +"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", true], + +["Coinbase of size 1"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", true], + +["Coinbase of size 101"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], + +["Null txin"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true], + +["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true] +] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json new file mode 100644 index 0000000..c609924 --- /dev/null +++ b/src/test/data/tx_valid.json @@ -0,0 +1,81 @@ +[ +["The following are deserialized transactions which are valid."], +["They are in the form"], +["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], +["serializedTransaction, enforceP2SH]"], +["Objects that are only a single string (like this one) are ignored"], + +["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"], +["See http://r6.ca/blog/20111119T211504Z.html"], +["It is also the first OP_CHECKMULTISIG transaction in standard form"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], + +["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It has an arbitrary extra byte stuffed into the signature at pos length - 2"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], + +["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"], +["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"], +[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]], +"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", true], + +["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"], +["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"], +[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"], +["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]], +"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", true], + +["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"]], +"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", true], + +["An invalid P2SH Transaction"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", false], + +["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true], + +["Tests for CTransaction::CheckTransaction()"], +["MAX_MONEY output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true], + +["MAX_MONEY output + 0 output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", true], + +["Coinbase of size 2"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", true], + +["Coinbase of size 100"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], + +["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true], + +["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true] +] diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index a6e8a10..f94f915 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -26,8 +26,8 @@ static const string strAddressBad("LRjyUS2uuieEPkhZNdQz8hE5YycxVEqSXA"); #ifdef KEY_TESTS_DUMPINFO void dumpKeyInfo(uint256 privkey) { - CSecret secret; - secret.resize(32); + CKey key; + key.resize(32); memcpy(&secret[0], &privkey, 32); vector sec; sec.resize(32); @@ -62,29 +62,24 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK( bsecret2C.SetString(strSecret2C)); BOOST_CHECK(!baddress1.SetString(strAddressBad)); - bool fCompressed; - CSecret secret1 = bsecret1.GetSecret (fCompressed); - BOOST_CHECK(fCompressed == false); - CSecret secret2 = bsecret2.GetSecret (fCompressed); - BOOST_CHECK(fCompressed == false); - CSecret secret1C = bsecret1C.GetSecret(fCompressed); - BOOST_CHECK(fCompressed == true); - CSecret secret2C = bsecret2C.GetSecret(fCompressed); - BOOST_CHECK(fCompressed == true); + CKey key1 = bsecret1.GetKey(); + BOOST_CHECK(key1.IsCompressed() == false); + CKey key2 = bsecret2.GetKey(); + BOOST_CHECK(key2.IsCompressed() == false); + CKey key1C = bsecret1C.GetKey(); + BOOST_CHECK(key1C.IsCompressed() == true); + CKey key2C = bsecret2C.GetKey(); + BOOST_CHECK(key1C.IsCompressed() == true); - BOOST_CHECK(secret1 == secret1C); - BOOST_CHECK(secret2 == secret2C); + CPubKey pubkey1 = key1. GetPubKey(); + CPubKey pubkey2 = key2. GetPubKey(); + CPubKey pubkey1C = key1C.GetPubKey(); + CPubKey pubkey2C = key2C.GetPubKey(); - CKey key1, key2, key1C, key2C; - key1.SetSecret(secret1, false); - key2.SetSecret(secret2, false); - key1C.SetSecret(secret1, true); - key2C.SetSecret(secret2, true); - - BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID())); - BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID())); - BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID())); - BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID())); + BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID())); + BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID())); + BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID())); + BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID())); for (int n=0; n<16; n++) { @@ -100,25 +95,25 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key1C.Sign(hashMsg, sign1C)); BOOST_CHECK(key2C.Sign(hashMsg, sign2C)); - BOOST_CHECK( key1.Verify(hashMsg, sign1)); - BOOST_CHECK(!key1.Verify(hashMsg, sign2)); - BOOST_CHECK( key1.Verify(hashMsg, sign1C)); - BOOST_CHECK(!key1.Verify(hashMsg, sign2C)); + BOOST_CHECK( pubkey1.Verify(hashMsg, sign1)); + BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2)); + BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C)); - BOOST_CHECK(!key2.Verify(hashMsg, sign1)); - BOOST_CHECK( key2.Verify(hashMsg, sign2)); - BOOST_CHECK(!key2.Verify(hashMsg, sign1C)); - BOOST_CHECK( key2.Verify(hashMsg, sign2C)); + BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1)); + BOOST_CHECK( pubkey2.Verify(hashMsg, sign2)); + BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C)); + BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C)); - BOOST_CHECK( key1C.Verify(hashMsg, sign1)); - BOOST_CHECK(!key1C.Verify(hashMsg, sign2)); - BOOST_CHECK( key1C.Verify(hashMsg, sign1C)); - BOOST_CHECK(!key1C.Verify(hashMsg, sign2C)); + BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1)); + BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2)); + BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C)); - BOOST_CHECK(!key2C.Verify(hashMsg, sign1)); - BOOST_CHECK( key2C.Verify(hashMsg, sign2)); - BOOST_CHECK(!key2C.Verify(hashMsg, sign1C)); - BOOST_CHECK( key2C.Verify(hashMsg, sign2C)); + BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1)); + BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2)); + BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C)); + BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C)); // compact signatures (with key recovery) @@ -129,18 +124,17 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); - CKey rkey1, rkey2, rkey1C, rkey2C; + CPubKey rkey1, rkey2, rkey1C, rkey2C; - BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1)); - BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2)); - BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C)); - BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C)); + BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1)); + BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2)); + BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C)); + BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C)); - - BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey()); - BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey()); - BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey()); - BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey()); + BOOST_CHECK(rkey1 == pubkey1); + BOOST_CHECK(rkey2 == pubkey2); + BOOST_CHECK(rkey1C == pubkey1C); + BOOST_CHECK(rkey2C == pubkey2C); } } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 5712b4a..b5f78d0 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,12 +1,206 @@ #include +#include "init.h" +#include "main.h" #include "uint256.h" #include "util.h" +#include "wallet.h" extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); BOOST_AUTO_TEST_SUITE(miner_tests) +static +struct { + unsigned char extranonce; + unsigned int nonce; +} blockinfo[] = { + {4, 0xa4ad9f65}, {2, 0x15cf2b27}, {1, 0x037620ac}, {1, 0x700d9c54}, + {2, 0xce79f74f}, {2, 0x52d9c194}, {1, 0x77bc3efc}, {2, 0xbb62c5e8}, + {2, 0x83ff997a}, {1, 0x48b984ee}, {1, 0xef925da0}, {2, 0x680d2979}, + {2, 0x08953af7}, {1, 0x087dd553}, {2, 0x210e2818}, {2, 0xdfffcdef}, + {1, 0xeea1b209}, {2, 0xba4a8943}, {1, 0xa7333e77}, {1, 0x344f3e2a}, + {3, 0xd651f08e}, {2, 0xeca3957f}, {2, 0xca35aa49}, {1, 0x6bb2065d}, + {2, 0x0170ee44}, {1, 0x6e12f4aa}, {2, 0x43f4f4db}, {2, 0x279c1c44}, + {2, 0xb5a50f10}, {2, 0xb3902841}, {2, 0xd198647e}, {2, 0x6bc40d88}, + {1, 0x633a9a1c}, {2, 0x9a722ed8}, {2, 0x55580d10}, {1, 0xd65022a1}, + {2, 0xa12ffcc8}, {1, 0x75a6a9c7}, {2, 0xfb7c80b7}, {1, 0xe8403e6c}, + {1, 0xe34017a0}, {3, 0x659e177b}, {2, 0xba5c40bf}, {5, 0x022f11ef}, + {1, 0xa9ab516a}, {5, 0xd0999ed4}, {1, 0x37277cb3}, {1, 0x830f735f}, + {1, 0xc6e3d947}, {2, 0x824a0c1b}, {1, 0x99962416}, {1, 0x75336f63}, + {1, 0xaacf0fea}, {1, 0xd6531aec}, {5, 0x7afcf541}, {5, 0x9d6fac0d}, + {1, 0x4cf5c4df}, {1, 0xabe0f2a0}, {6, 0x4a3dac18}, {2, 0xf265febe}, + {2, 0x1bc9f23f}, {1, 0xad49ab71}, {1, 0x9f2d8923}, {1, 0x15acb65d}, + {2, 0xd1cecb52}, {2, 0xf856808b}, {1, 0x0fa96e29}, {1, 0xe063ecbc}, + {1, 0x78d926c6}, {5, 0x3e38ad35}, {5, 0x73901915}, {1, 0x63424be0}, + {1, 0x6d6b0a1d}, {2, 0x888ba681}, {2, 0xe96b0714}, {1, 0xb7fcaa55}, + {2, 0x19c106eb}, {1, 0x5aa13484}, {2, 0x5bf4c2f3}, {2, 0x94d401dd}, + {1, 0xa9bc23d9}, {1, 0x3a69c375}, {1, 0x56ed2006}, {5, 0x85ba6dbd}, + {1, 0xfd9b2000}, {1, 0x2b2be19a}, {1, 0xba724468}, {1, 0x717eb6e5}, + {1, 0x70de86d9}, {1, 0x74e23a42}, {1, 0x49e92832}, {2, 0x6926dbb9}, + {0, 0x64452497}, {1, 0x54306d6f}, {2, 0x97ebf052}, {2, 0x55198b70}, + {2, 0x03fe61f0}, {1, 0x98f9e67f}, {1, 0xc0842a09}, {1, 0xdfed39c5}, + {1, 0x3144223e}, {1, 0xb3d12f84}, {1, 0x7366ceb7}, {5, 0x6240691b}, + {2, 0xd3529b57}, {1, 0xf4cae3b1}, {1, 0x5b1df222}, {1, 0xa16a5c70}, + {2, 0xbbccedc6}, {2, 0xfe38d0ef}, +}; + +// NOTE: These tests rely on CreateNewBlock doing its own self-validation! +BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) +{ + CReserveKey reservekey(pwalletMain); + CBlockTemplate *pblocktemplate; + CTransaction tx; + CScript script; + uint256 hash; + + // Simple block creation, nothing special yet: + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + + // We can't make transactions until we have inputs + // Therefore, load 100 blocks :) + std::vectortxFirst; + for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) + { + CBlock *pblock = &pblocktemplate->block; // pointer for convenience + pblock->nVersion = 1; + pblock->nTime = pindexBest->GetMedianTimePast()+1; + pblock->vtx[0].vin[0].scriptSig = CScript(); + pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce); + pblock->vtx[0].vin[0].scriptSig.push_back(pindexBest->nHeight); + pblock->vtx[0].vout[0].scriptPubKey = CScript(); + if (txFirst.size() < 2) + txFirst.push_back(new CTransaction(pblock->vtx[0])); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + pblock->nNonce = blockinfo[i].nonce; + CValidationState state; + BOOST_CHECK(ProcessBlock(state, NULL, pblock)); + BOOST_CHECK(state.IsValid()); + pblock->hashPrevBlock = pblock->GetHash(); + } + delete pblocktemplate; + + // Just to make sure we can still make simple blocks + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + + // block sigops > limit: 1000 CHECKMULTISIG + 1 + tx.vin.resize(1); + // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG + tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1; + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].prevout.n = 0; + tx.vout.resize(1); + tx.vout[0].nValue = 5000000000LL; + for (unsigned int i = 0; i < 1001; ++i) + { + tx.vout[0].nValue -= 1000000; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // block size > limit + tx.vin[0].scriptSig = CScript(); + // 18 * (520char + DROP) + OP_1 = 9433 bytes + std::vector vchData(520); + for (unsigned int i = 0; i < 18; ++i) + tx.vin[0].scriptSig << vchData << OP_DROP; + tx.vin[0].scriptSig << OP_1; + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vout[0].nValue = 5000000000LL; + for (unsigned int i = 0; i < 128; ++i) + { + tx.vout[0].nValue -= 10000000; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // orphan in mempool + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // child with higher priority than parent + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vin[0].prevout.hash = txFirst[1]->GetHash(); + tx.vout[0].nValue = 4900000000LL; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + tx.vin.resize(2); + tx.vin[1].scriptSig = CScript() << OP_1; + tx.vin[1].prevout.hash = txFirst[0]->GetHash(); + tx.vin[1].prevout.n = 0; + tx.vout[0].nValue = 5900000000LL; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // coinbase in mempool + tx.vin.resize(1); + tx.vin[0].prevout.SetNull(); + tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; + tx.vout[0].nValue = 0; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // invalid (pre-p2sh) txn in mempool + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].prevout.n = 0; + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout[0].nValue = 4900000000LL; + script = CScript() << OP_0; + tx.vout[0].scriptPubKey.SetDestination(script.GetID()); + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + tx.vin[0].scriptSig = CScript() << (std::vector)script; + tx.vout[0].nValue -= 1000000; + hash = tx.GetHash(); + mempool.addUnchecked(hash,tx); + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // double spend txn pair in mempool + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout[0].nValue = 4900000000LL; + tx.vout[0].scriptPubKey = CScript() << OP_1; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vout[0].scriptPubKey = CScript() << OP_2; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + mempool.clear(); + + // subsidy changing + int nHeight = pindexBest->nHeight; + pindexBest->nHeight = 209999; + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + pindexBest->nHeight = 210000; + BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + delete pblocktemplate; + pindexBest->nHeight = nHeight; +} + BOOST_AUTO_TEST_CASE(sha256transform_equality) { unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 6bc5e3b..9ef932b 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -20,8 +20,6 @@ using namespace boost::assign; typedef vector valtype; extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); BOOST_AUTO_TEST_SUITE(multisig_tests) @@ -32,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, CScript result; result << OP_0; // CHECKMULTISIG bug workaround - BOOST_FOREACH(CKey key, keys) + BOOST_FOREACH(const CKey &key, keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); @@ -44,6 +42,8 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, BOOST_AUTO_TEST_CASE(multisig_verify) { + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; + CKey key[4]; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); @@ -80,19 +80,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys.clear(); keys += key[0],key[1]; // magic operator+= from boost.assign s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, 0)); + BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags, 0)); for (int i = 0; i < 4; i++) { keys.clear(); keys += key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 1: %d", i)); keys.clear(); keys += key[1],key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 2: %d", i)); } // Test a OR b: @@ -102,16 +102,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys += key[i]; s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i)); else - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i)); } s.clear(); s << OP_0 << OP_0; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0)); + BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0)); s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0)); + BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0)); for (int i = 0; i < 4; i++) @@ -121,9 +121,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys += key[i],key[j]; s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 1: %d %d", i, j)); else - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 2: %d %d", i, j)); } } @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CScript s; s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4); + BOOST_CHECK_EQUAL(solutions.size(), 4U); CTxDestination addr; BOOST_CHECK(!ExtractDestination(s, addr)); BOOST_CHECK(IsMine(keystore, s)); @@ -229,7 +229,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CScript s; s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4); + BOOST_CHECK_EQUAL(solutions.size(), 4U); vector addrs; int nRequired; BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 502369c..d7a0304 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -52,20 +52,20 @@ bool static TestSplitHost(string test, string host, int port) BOOST_AUTO_TEST_CASE(netbase_splithost) { - BOOST_CHECK(TestSplitHost("www.casinocoin.org", "www.casinocoin.org", -1)); - BOOST_CHECK(TestSplitHost("[www.casinocoin.org]", "www.casinocoin.org", -1)); - BOOST_CHECK(TestSplitHost("www.casinocoin.org:80", "www.casinocoin.org", 80)); - BOOST_CHECK(TestSplitHost("[www.casinocoin.org]:80", "www.casinocoin.org", 80)); + BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1)); + BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1)); + BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80)); + BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80)); BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1)); - BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333)); + BOOST_CHECK(TestSplitHost("127.0.0.1:47950", "127.0.0.1", 47950)); BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1)); - BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333)); + BOOST_CHECK(TestSplitHost("[127.0.0.1]:47950", "127.0.0.1", 47950)); BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1)); - BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333)); - BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333)); - BOOST_CHECK(TestSplitHost("::8333", "::8333", -1)); - BOOST_CHECK(TestSplitHost(":8333", "", 8333)); - BOOST_CHECK(TestSplitHost("[]:8333", "", 8333)); + BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:47950", "::ffff:127.0.0.1", 47950)); + BOOST_CHECK(TestSplitHost("[::]:47950", "::", 47950)); + BOOST_CHECK(TestSplitHost("::47950", "::47950", -1)); + BOOST_CHECK(TestSplitHost(":47950", "", 47950)); + BOOST_CHECK(TestSplitHost("[]:47950", "", 47950)); BOOST_CHECK(TestSplitHost("", "", -1)); } @@ -80,10 +80,10 @@ bool static TestParse(string src, string canon) BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) { BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535")); - BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333")); + BOOST_CHECK(TestParse("127.0.0.1:47950", "127.0.0.1:47950")); BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535")); BOOST_CHECK(TestParse("::", "[::]:65535")); - BOOST_CHECK(TestParse("[::]:8333", "[::]:8333")); + BOOST_CHECK(TestParse("[::]:47950", "[::]:47950")); BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); BOOST_CHECK(TestParse(":::", "")); } diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp new file mode 100644 index 0000000..cf09421 --- /dev/null +++ b/src/test/pmt_tests.cpp @@ -0,0 +1,98 @@ +#include + +#include "uint256.h" +#include "main.h" + +using namespace std; + +class CPartialMerkleTreeTester : public CPartialMerkleTree +{ +public: + // flip one bit in one of the hashes - this should break the authentication + void Damage() { + unsigned int n = rand() % vHash.size(); + int bit = rand() % 256; + uint256 &hash = vHash[n]; + hash ^= ((uint256)1 << bit); + } +}; + +BOOST_AUTO_TEST_SUITE(pmt_tests) + +BOOST_AUTO_TEST_CASE(pmt_test1) +{ + static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; + + for (int n = 0; n < 12; n++) { + unsigned int nTx = nTxCounts[n]; + + // build a block with some dummy transactions + CBlock block; + for (unsigned int j=0; j vTxid(nTx, 0); + for (unsigned int j=0; j 1) { + nTx_ = (nTx_+1)/2; + nHeight++; + } + + // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128 + for (int att = 1; att < 15; att++) { + // build random subset of txid's + std::vector vMatch(nTx, false); + std::vector vMatchTxid1; + for (unsigned int j=0; j(nTx, 1 + vMatchTxid1.size()*nHeight); + BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8); + + // deserialize into a tester copy + CPartialMerkleTreeTester pmt2; + ss >> pmt2; + + // extract merkle root and matched txids from copy + std::vector vMatchTxid2; + uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2); + + // check that it has the same merkle root as the original, and a valid one + BOOST_CHECK(merkleRoot1 == merkleRoot2); + BOOST_CHECK(merkleRoot2 != 0); + + // check that it contains the matched transactions (in the same order!) + BOOST_CHECK(vMatchTxid1 == vMatchTxid2); + + // check that random bit flips break the authentication + for (int j=0; j<4; j++) { + CPartialMerkleTreeTester pmt3(pmt2); + pmt3.Damage(); + std::vector vMatchTxid3; + uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3); + BOOST_CHECK(merkleRoot3 != merkleRoot1); + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index e6c00e3..baeea42 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -1,5 +1,6 @@ -#include +#include #include +#include #include "base58.h" #include "util.h" @@ -17,19 +18,12 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) result.push_back(nRequired); Array addresses; if (address1) addresses.push_back(address1); - if (address2) addresses.push_back(address1); + if (address2) addresses.push_back(address2); result.push_back(addresses); return result; } -// This can be removed this when addmultisigaddress is enabled on main net: -struct TestNetFixture -{ - TestNetFixture() { fTestNet = true; } - ~TestNetFixture() { fTestNet = false; } -}; - -BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture) +BOOST_AUTO_TEST_CASE(rpc_addmultisig) { rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; @@ -66,4 +60,112 @@ BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture) BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); } +static Value CallRPC(string args) +{ + vector vArgs; + boost::split(vArgs, args, boost::is_any_of(" \t")); + string strMethod = vArgs[0]; + vArgs.erase(vArgs.begin()); + Array params = RPCConvertValues(strMethod, vArgs); + + rpcfn_type method = tableRPC[strMethod]->actor; + try { + Value result = (*method)(params, false); + return result; + } + catch (Object& objError) + { + throw runtime_error(find_value(objError, "message").get_str()); + } +} + +BOOST_AUTO_TEST_CASE(rpc_wallet) +{ + // Test RPC calls for various wallet statistics + Value r; + + 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()); + + 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); + + 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); +} + + +BOOST_AUTO_TEST_CASE(rpc_rawparams) +{ + // Test raw transaction API argument handling + Value 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("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_NO_THROW(CallRPC("createrawtransaction [] {}")); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), 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_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(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); + + // 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_AUTO_TEST_CASE(rpc_rawsign) +{ + Value r; + // input is a 1-of-2 multisig (so is output): + string prevout = + "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\"," + "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\"," + "\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]"; + r = CallRPC(string("createrawtransaction ")+prevout+" "+ + "{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}"); + string notsigned = r.get_str(); + string privkey1 = "\"T6hoRM7L8u4f9vHd4eGMAmwV6AMCE11PvYi7YjrdegG223kw64r1\""; + string privkey2 = "\"T5Xu6pe5iqQYqXGxhcY2QEFr7NNoVQ5R6A4abpswunCTF9w85g8V\""; + r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]"); + BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); + r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]"); + BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index f7bf5df..65f0ad0 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -13,8 +13,6 @@ using namespace std; // Test routines internal to script.cpp: extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); // Helpers: static std::vector @@ -40,7 +38,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, 0); + return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); } @@ -80,7 +78,9 @@ BOOST_AUTO_TEST_CASE(sign) for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = evalScripts[i]; + txFrom.vout[i].nValue = COIN; txFrom.vout[i+4].scriptPubKey = standardScripts[i]; + txFrom.vout[i+4].nValue = COIN; } BOOST_CHECK(txFrom.IsStandard()); @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE(sign) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = VerifySignature(txFrom, txTo[i], 0, true, 0); + bool sigOK = VerifySignature(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(norecurse) // Should not verify, because it will try to execute OP_INVALIDOPCODE BOOST_CHECK(!Verify(scriptSig, p2sh, true)); - // Try to recurse, and verification should succeed because + // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: CScript p2sh2; p2sh2.SetDestination(p2sh.GetID()); @@ -145,19 +145,19 @@ BOOST_AUTO_TEST_CASE(set) // Test the CScript::Set* methods CBasicKeyStore keystore; CKey key[4]; - std::vector keys; + std::vector keys; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keys.push_back(key[i]); + keys.push_back(key[i].GetPubKey()); } CScript inner[4]; inner[0].SetDestination(key[0].GetPubKey().GetID()); - inner[1].SetMultisig(2, std::vector(keys.begin(), keys.begin()+2)); - inner[2].SetMultisig(1, std::vector(keys.begin(), keys.begin()+2)); - inner[3].SetMultisig(2, std::vector(keys.begin(), keys.begin()+3)); + inner[1].SetMultisig(2, std::vector(keys.begin(), keys.begin()+2)); + inner[2].SetMultisig(1, std::vector(keys.begin(), keys.begin()+2)); + inner[3].SetMultisig(2, std::vector(keys.begin(), keys.begin()+3)); CScript outer[4]; for (int i = 0; i < 4; i++) @@ -171,6 +171,7 @@ BOOST_AUTO_TEST_CASE(set) for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = outer[i]; + txFrom.vout[i].nValue = CENT; } BOOST_CHECK(txFrom.IsStandard()); @@ -181,7 +182,7 @@ BOOST_AUTO_TEST_CASE(set) txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); - txTo[i].vout[0].nValue = 1; + txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].scriptPubKey = inner[i]; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); } @@ -225,7 +226,7 @@ BOOST_AUTO_TEST_CASE(is) BOOST_AUTO_TEST_CASE(switchover) { - // Test switchover code + // Test switch over code CScript notValid; notValid << OP_11 << OP_12 << OP_EQUALVERIFY; CScript scriptSig; @@ -243,15 +244,16 @@ BOOST_AUTO_TEST_CASE(switchover) BOOST_AUTO_TEST_CASE(AreInputsStandard) { - std::map > mapInputs; + CCoinsView coinsDummy; + CCoinsViewCache coins(coinsDummy); CBasicKeyStore keystore; CKey key[3]; - vector keys; + vector keys; for (int i = 0; i < 3; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keys.push_back(key[i]); + keys.push_back(key[i].GetPubKey()); } CTransaction txFrom; @@ -264,23 +266,29 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CScript pay1of3; pay1of3.SetMultisig(1, keys); txFrom.vout[0].scriptPubKey = payScriptHash1; + txFrom.vout[0].nValue = 1000; txFrom.vout[1].scriptPubKey = pay1; + txFrom.vout[1].nValue = 2000; txFrom.vout[2].scriptPubKey = pay1of3; + txFrom.vout[2].nValue = 3000; // Last three non-standard: CScript empty; keystore.AddCScript(empty); txFrom.vout[3].scriptPubKey = empty; + txFrom.vout[3].nValue = 4000; // Can't use SetPayToScriptHash, it checks for the empty Script. So: txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL; + txFrom.vout[4].nValue = 5000; CScript oneOfEleven; oneOfEleven << OP_1; for (int i = 0; i < 11; i++) oneOfEleven << key[0].GetPubKey(); oneOfEleven << OP_11 << OP_CHECKMULTISIG; txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID()); + txFrom.vout[5].nValue = 6000; - mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom); + coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0)); CTransaction txTo; txTo.vout.resize(1); @@ -297,21 +305,22 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txTo.vin[2].prevout.hash = txFrom.GetHash(); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2)); - BOOST_CHECK(txTo.AreInputsStandard(mapInputs)); - BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1); + BOOST_CHECK(txTo.AreInputsStandard(coins)); + BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(coins), 1U); // Make sure adding crap to the scriptSigs makes them non-standard: for (int i = 0; i < 3; i++) { CScript t = txTo.vin[i].scriptSig; txTo.vin[i].scriptSig = (CScript() << 11) + t; - BOOST_CHECK(!txTo.AreInputsStandard(mapInputs)); + BOOST_CHECK(!txTo.AreInputsStandard(coins)); txTo.vin[i].scriptSig = t; } CTransaction txToNonStd; txToNonStd.vout.resize(1); txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); + txToNonStd.vout[0].nValue = 1000; txToNonStd.vin.resize(2); txToNonStd.vin[0].prevout.n = 4; txToNonStd.vin[0].prevout.hash = txFrom.GetHash(); @@ -320,11 +329,11 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd.vin[1].prevout.hash = txFrom.GetHash(); txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven); - BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs)); - BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(mapInputs), 11); + BOOST_CHECK(!txToNonStd.AreInputsStandard(coins)); + BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(coins), 11U); txToNonStd.vin[0].scriptSig.clear(); - BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs)); + BOOST_CHECK(!txToNonStd.AreInputsStandard(coins)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 61d9a64..e7ad526 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -20,8 +20,8 @@ using namespace json_spirit; using namespace boost::algorithm; extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); + +static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; CScript ParseScript(string s) @@ -79,7 +79,7 @@ ParseScript(string s) { BOOST_ERROR("Parse error: " << s); return CScript(); - } + } } return result; @@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(script_valid) CScript scriptPubKey = ParseScript(scriptPubKeyString); CTransaction tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest); + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, flags, SIGHASH_NONE), strTest); } } @@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) CScript scriptPubKey = ParseScript(scriptPubKeyString); CTransaction tx; - BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest); + BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, flags, SIGHASH_NONE), strTest); } } @@ -181,18 +181,18 @@ BOOST_AUTO_TEST_CASE(script_PushData) static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, true, 0)); vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, true, 0)); BOOST_CHECK(pushdata1Stack == directStack); vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, true, 0)); BOOST_CHECK(pushdata2Stack == directStack); vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, true, 0)); BOOST_CHECK(pushdata4Stack == directStack); } @@ -206,12 +206,12 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac // NOTE: CHECKMULTISIG has an unfortunate bug; it requires // one extra item on the stack, before the signatures. // Putting OP_0 on the stack is the workaround; - // fixing the bug would mean splitting the blockchain (old + // fixing the bug would mean splitting the block chain (old // clients would not accept new CHECKMULTISIG transactions, // and vice-versa) // result << OP_0; - BOOST_FOREACH(CKey key, keys) + BOOST_FOREACH(const CKey &key, keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); @@ -221,7 +221,7 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac return result; } CScript -sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction) +sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) { std::vector keys; keys.push_back(key); @@ -250,15 +250,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) txTo12.vout[0].nValue = 1; CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, 0)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, flags, 0)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, flags, 0)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) @@ -286,46 +286,46 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) std::vector keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, 0)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, 0)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, 0)); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, flags, 0)); 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, txTo23, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, flags, 0)); 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, txTo23, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, flags, 0)); 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, txTo23, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, flags, 0)); 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, txTo23, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, flags, 0)); 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, txTo23, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, 0)); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, flags, 0)); } BOOST_AUTO_TEST_CASE(script_combineSigs) @@ -333,11 +333,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) // Test the CombineSignatures function CBasicKeyStore keystore; vector keys; + vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; key.MakeNewKey(i%2 == 1); keys.push_back(key); + pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } @@ -390,7 +392,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(combined == scriptSig); // Hardest case: Multisig 2-of-3 - scriptPubKey.SetMultisig(2, keys); + scriptPubKey.SetMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, txFrom, txTo, 0); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); diff --git a/src/test/scrypt_tests.cpp b/src/test/scrypt_tests.cpp new file mode 100644 index 0000000..ad9059d --- /dev/null +++ b/src/test/scrypt_tests.cpp @@ -0,0 +1,33 @@ +#include + +#include "util.h" +#include "scrypt.h" + +BOOST_AUTO_TEST_SUITE(scrypt_tests) + +BOOST_AUTO_TEST_CASE(scrypt_hashtest) +{ + // Test Scrypt hash with known inputs against expected outputs + #define HASHCOUNT 5 + const char* inputhex[HASHCOUNT] = { "020000004c1271c211717198227392b029a64a7971931d351b387bb80db027f270411e398a07046f7d4a08dd815412a8712f874a7ebf0507e3878bd24e20a3b73fd750a667d2f451eac7471b00de6659", "0200000011503ee6a855e900c00cfdd98f5f55fffeaee9b6bf55bea9b852d9de2ce35828e204eef76acfd36949ae56d1fbe81c1ac9c0209e6331ad56414f9072506a77f8c6faf551eac7471b00389d01", "02000000a72c8a177f523946f42f22c3e86b8023221b4105e8007e59e81f6beb013e29aaf635295cb9ac966213fb56e046dc71df5b3f7f67ceaeab24038e743f883aff1aaafaf551eac7471b0166249b", "010000007824bc3a8a1b4628485eee3024abd8626721f7f870f8ad4d2f33a27155167f6a4009d1285049603888fe85a84b6c803a53305a8d497965a5e896e1a00568359589faf551eac7471b0065434e", "0200000050bfd4e4a307a8cb6ef4aef69abc5c0f2d579648bd80d7733e1ccc3fbc90ed664a7f74006cb11bde87785f229ecd366c2d4e44432832580e0608c579e4cb76f383f7f551eac7471b00c36982" }; + const char* expected[HASHCOUNT] = { "00000000002bef4107f882f6115e0b01f348d21195dacd3582aa2dabd7985806" , "00000000003a0d11bdd5eb634e08b7feddcfbbf228ed35d250daf19f1c88fc94", "00000000000b40f895f288e13244728a6c2d9d59d8aff29c65f8dd5114a8ca81", "00000000003007005891cd4923031e99d8e8d72f6e8e7edc6a86181897e105fe", "000000000018f0b426a4afc7130ccb47fa02af730d345b4fe7c7724d3800ec8c" }; +#if defined(USE_SSE2) + scrypt_detect_sse2(); +#endif + uint256 scrypthash; + std::vector inputbytes; + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + for (int i = 0; i < HASHCOUNT; i++) { + inputbytes = ParseHex(inputhex[i]); +#if defined(USE_SSE2) + // Test SSE2 scrypt + scrypt_1024_1_1_256_sp_sse2((const char*)&inputbytes[0], BEGIN(scrypthash), scratchpad); + BOOST_CHECK_EQUAL(scrypthash.ToString().c_str(), expected[i]); +#endif + // Test generic scrypt + scrypt_1024_1_1_256_sp_generic((const char*)&inputbytes[0], BEGIN(scrypthash), scratchpad); + BOOST_CHECK_EQUAL(scrypthash.ToString().c_str(), expected[i]); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp new file mode 100644 index 0000000..19ffdca --- /dev/null +++ b/src/test/serialize_tests.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include + +#include "serialize.h" + +using namespace std; + +BOOST_AUTO_TEST_SUITE(serialize_tests) + +BOOST_AUTO_TEST_CASE(varints) +{ + // encode + + CDataStream ss(SER_DISK, 0); + CDataStream::size_type size = 0; + for (int i = 0; i < 100000; i++) { + ss << VARINT(i); + size += ::GetSerializeSize(VARINT(i), 0, 0); + BOOST_CHECK(size == ss.size()); + } + + for (uint64 i = 0; i < 100000000000ULL; i += 999999937) { + ss << VARINT(i); + size += ::GetSerializeSize(VARINT(i), 0, 0); + BOOST_CHECK(size == ss.size()); + } + + // decode + for (int i = 0; i < 100000; i++) { + int j = -1; + ss >> VARINT(j); + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } + + for (uint64 i = 0; i < 100000000000ULL; i += 999999937) { + uint64 j = -1; + ss >> VARINT(j); + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 59673f9..5a87f17 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -21,40 +21,40 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) { // Test CScript::GetSigOpCount() CScript s1; - BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0); - BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0U); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U); uint160 dummy; s1 << OP_1 << dummy << dummy << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U); s1 << OP_IF << OP_CHECKSIG << OP_ENDIF; - BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3); - BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U); CScript p2sh; p2sh.SetDestination(s1.GetID()); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); - std::vector keys; + std::vector keys; for (int i = 0; i < 3; i++) { CKey k; k.MakeNewKey(true); - keys.push_back(k); + keys.push_back(k.GetPubKey()); } CScript s2; s2.SetMultisig(1, keys); - BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3); - BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20); + BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U); + BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U); p2sh.SetDestination(s2.GetID()); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U); CScript scriptSig2; scriptSig2 << OP_1 << dummy << dummy << Serialize(s2); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 96d63bf..6c7e74e 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -1,8 +1,12 @@ -#define BOOST_TEST_MODULE Bitcoin Test Suite +#define BOOST_TEST_MODULE CasinoCoin Test Suite #include +#include +#include "db.h" +#include "txdb.h" #include "main.h" #include "wallet.h" +#include "util.h" CWallet* pwalletMain; CClientUIInterface uiInterface; @@ -11,16 +15,40 @@ extern bool fPrintToConsole; extern void noui_connect(); struct TestingSetup { + CCoinsViewDB *pcoinsdbview; + boost::filesystem::path pathTemp; + boost::thread_group threadGroup; + TestingSetup() { - fPrintToConsole = true; // don't want to write to debug.log file + fPrintToDebugger = true; // don't want to write to debug.log file noui_connect(); - pwalletMain = new CWallet(); + bitdb.MakeMock(); + pathTemp = GetTempPath() / strprintf("test_casinocoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); + pblocktree = new CBlockTreeDB(1 << 20, true); + pcoinsdbview = new CCoinsViewDB(1 << 23, true); + pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + InitBlockIndex(); + bool fFirstRun; + pwalletMain = new CWallet("wallet.dat"); + pwalletMain->LoadWallet(fFirstRun); RegisterWallet(pwalletMain); + nScriptCheckThreads = 3; + for (int i=0; i < nScriptCheckThreads-1; i++) + threadGroup.create_thread(&ThreadScriptCheck); } ~TestingSetup() { + threadGroup.interrupt_all(); + threadGroup.join_all(); delete pwalletMain; pwalletMain = NULL; + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; + bitdb.Flush(true); + boost::filesystem::remove_all(pathTemp); } }; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index be0d976..88f8cef 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,12 +1,159 @@ +#include +#include #include +#include "json/json_spirit_writer_template.h" #include "main.h" #include "wallet.h" using namespace std; +using namespace json_spirit; + +// In script_tests.cpp +extern Array read_json(const std::string& filename); +extern CScript ParseScript(string s); BOOST_AUTO_TEST_SUITE(transaction_tests) +BOOST_AUTO_TEST_CASE(tx_valid) +{ + // Read tests from test/data/tx_valid.json + // Format is an array of arrays + // Inner arrays are either [ "comment" ] + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // ... where all scripts are stringified scripts. + Array tests = read_json("tx_valid.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + string strTest = write_string(tv, false); + if (test[0].type() == array_type) + { + if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + map mapprevOutScriptPubKeys; + Array inputs = test[0].get_array(); + bool fValid = true; + BOOST_FOREACH(Value& input, inputs) + { + if (input.type() != array_type) + { + fValid = false; + break; + } + Array vinput = input.get_array(); + if (vinput.size() != 3) + { + fValid = false; + break; + } + + mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str()); + } + if (!fValid) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + string transaction = test[1].get_str(); + CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + stream >> tx; + + CValidationState state; + BOOST_CHECK_MESSAGE(tx.CheckTransaction(state), strTest); + BOOST_CHECK(state.IsValid()); + + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) + { + BOOST_ERROR("Bad test: " << strTest); + break; + } + + BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0), strTest); + } + } + } +} + +BOOST_AUTO_TEST_CASE(tx_invalid) +{ + // Read tests from test/data/tx_invalid.json + // Format is an array of arrays + // Inner arrays are either [ "comment" ] + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // ... where all scripts are stringified scripts. + Array tests = read_json("tx_invalid.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + string strTest = write_string(tv, false); + if (test[0].type() == array_type) + { + if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + map mapprevOutScriptPubKeys; + Array inputs = test[0].get_array(); + bool fValid = true; + BOOST_FOREACH(Value& input, inputs) + { + if (input.type() != array_type) + { + fValid = false; + break; + } + Array vinput = input.get_array(); + if (vinput.size() != 3) + { + fValid = false; + break; + } + + mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str()); + } + if (!fValid) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + string transaction = test[1].get_str(); + CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + stream >> tx; + + CValidationState state; + fValid = tx.CheckTransaction(state) && state.IsValid(); + + for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) + { + if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) + { + BOOST_ERROR("Bad test: " << strTest); + break; + } + + fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); + } + + BOOST_CHECK_MESSAGE(!fValid, strTest); + } + } +} + BOOST_AUTO_TEST_CASE(basic_transaction_tests) { // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) @@ -15,11 +162,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CTransaction tx; stream >> tx; - BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid."); + CValidationState state; + BOOST_CHECK_MESSAGE(tx.CheckTransaction(state) && state.IsValid(), "Simple deserialized transaction should be valid."); // Check that duplicate txins fail tx.vin.push_back(tx.vin[0]); - BOOST_CHECK_MESSAGE(!tx.CheckTransaction(), "Transaction with duplicate txins should be invalid."); + BOOST_CHECK_MESSAGE(!tx.CheckTransaction(state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); } // @@ -29,7 +177,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) // paid to a TX_PUBKEYHASH. // static std::vector -SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) +SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet) { std::vector dummyTransactions; dummyTransactions.resize(2); @@ -48,14 +196,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG; dummyTransactions[0].vout[1].nValue = 50*CENT; dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG; - inputsRet[dummyTransactions[0].GetHash()] = make_pair(CTxIndex(), dummyTransactions[0]); + coinsRet.SetCoins(dummyTransactions[0].GetHash(), CCoins(dummyTransactions[0], 0)); dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21*CENT; dummyTransactions[1].vout[0].scriptPubKey.SetDestination(key[2].GetPubKey().GetID()); dummyTransactions[1].vout[1].nValue = 22*CENT; dummyTransactions[1].vout[1].scriptPubKey.SetDestination(key[3].GetPubKey().GetID()); - inputsRet[dummyTransactions[1].GetHash()] = make_pair(CTxIndex(), dummyTransactions[1]); + coinsRet.SetCoins(dummyTransactions[1].GetHash(), CCoins(dummyTransactions[1], 0)); return dummyTransactions; } @@ -63,8 +211,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) BOOST_AUTO_TEST_CASE(test_Get) { CBasicKeyStore keystore; - MapPrevTx dummyInputs; - std::vector dummyTransactions = SetupDummyInputs(keystore, dummyInputs); + CCoinsView coinsDummy; + CCoinsViewCache coins(coinsDummy); + std::vector dummyTransactions = SetupDummyInputs(keystore, coins); CTransaction t1; t1.vin.resize(3); @@ -81,40 +230,47 @@ BOOST_AUTO_TEST_CASE(test_Get) t1.vout[0].nValue = 90*CENT; t1.vout[0].scriptPubKey << OP_1; - BOOST_CHECK(t1.AreInputsStandard(dummyInputs)); - BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT); + BOOST_CHECK(t1.AreInputsStandard(coins)); + BOOST_CHECK_EQUAL(t1.GetValueIn(coins), (50+21+22)*CENT); // Adding extra junk to the scriptSig should make it non-standard: t1.vin[0].scriptSig << OP_11; - BOOST_CHECK(!t1.AreInputsStandard(dummyInputs)); + BOOST_CHECK(!t1.AreInputsStandard(coins)); // ... as should not having enough: t1.vin[0].scriptSig = CScript(); - BOOST_CHECK(!t1.AreInputsStandard(dummyInputs)); + BOOST_CHECK(!t1.AreInputsStandard(coins)); } -BOOST_AUTO_TEST_CASE(test_GetThrow) +BOOST_AUTO_TEST_CASE(test_IsStandard) { CBasicKeyStore keystore; - MapPrevTx dummyInputs; - std::vector dummyTransactions = SetupDummyInputs(keystore, dummyInputs); + CCoinsView coinsDummy; + CCoinsViewCache coins(coinsDummy); + std::vector dummyTransactions = SetupDummyInputs(keystore, coins); - MapPrevTx missingInputs; + CTransaction t; + t.vin.resize(1); + t.vin[0].prevout.hash = dummyTransactions[0].GetHash(); + t.vin[0].prevout.n = 1; + t.vin[0].scriptSig << std::vector(65, 0); + t.vout.resize(1); + t.vout[0].nValue = 90*CENT; + CKey key; + key.MakeNewKey(true); + t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - CTransaction t1; - t1.vin.resize(3); - t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); - t1.vin[0].prevout.n = 0; - t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();; - t1.vin[1].prevout.n = 0; - t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();; - t1.vin[2].prevout.n = 1; - t1.vout.resize(2); - t1.vout[0].nValue = 90*CENT; - t1.vout[0].scriptPubKey << OP_1; + BOOST_CHECK(t.IsStandard()); - BOOST_CHECK_THROW(t1.AreInputsStandard(missingInputs), runtime_error); - BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error); + t.vout[0].nValue = 5011; // dust + // CasinoCoin does not enforce isDust(). Per dust fees are considered sufficient as deterrant. + // BOOST_CHECK(!t.IsStandard()); + + t.vout[0].nValue = 6011; // not dust + BOOST_CHECK(t.IsStandard()); + + t.vout[0].scriptPubKey = CScript() << OP_1; + BOOST_CHECK(!t.IsStandard()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 2bfda61..e224776 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -103,11 +103,13 @@ BOOST_AUTO_TEST_CASE(util_HexStr) BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat) { - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00"); - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07"); +/*These are platform-dependant and thus removed to avoid useless test failures + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0), "1970-01-01 00:00:00"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0x7FFFFFFF), "2038-01-19 03:14:07"); // Formats used within Bitcoin - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17"); - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 1317425777), "2011-09-30 23:36:17"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M", 1317425777), "2011-09-30 23:36"); +*/ } BOOST_AUTO_TEST_CASE(util_ParseParameters) @@ -259,4 +261,45 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_CHECK(!IsHex("0x0000")); } +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. + int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.); + //mask is 2^ceil(log2(mod))-1 + while(mask=(uint32_t)mod); + count += rval==0; + } + BOOST_CHECK(count<=10000/mod+err); + BOOST_CHECK(count>=10000/mod-err); + } +} + +BOOST_AUTO_TEST_CASE(util_TimingResistantEqual) +{ + BOOST_CHECK(TimingResistantEqual(std::string(""), std::string(""))); + BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string(""))); + BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc"))); + BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa"))); + BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a"))); + BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc"))); + BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba"))); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index 2f6da93..a14f6b2 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -21,13 +21,12 @@ static vector vCoins; static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { - static int i; - CTransaction* tx = new CTransaction; - tx->nLockTime = i++; // so all transactions get different hashes - tx->vout.resize(nInput+1); - tx->vout[nInput].nValue = nValue; - CWalletTx* wtx = new CWalletTx(&wallet, *tx); - delete tx; + static int nextLockTime = 0; + CTransaction 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, tx); if (fIsFromMe) { // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(), @@ -55,8 +54,8 @@ static bool equal_sets(CoinSet a, CoinSet b) BOOST_AUTO_TEST_CASE(coin_selection_tests) { - static CoinSet setCoinsRet, setCoinsRet2; - static int64 nValueRet; + CoinSet setCoinsRet, setCoinsRet2; + int64 nValueRet; // test multiple times to allow for differences in the shuffle order for (int i = 0; i < RUN_TESTS; i++) @@ -104,22 +103,22 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // 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_GT(nValueRet, 34 * CENT); // but should get more than 34 cents - BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible) + 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_EQUAL(nValueRet, 7 * CENT); - BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); + 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(nValueRet == 8 * CENT); - BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); + 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_EQUAL(nValueRet, 10 * CENT); - BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin empty_wallet(); @@ -137,26 +136,26 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // 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_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin - BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + 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_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins - BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); + 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_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin - BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); // because in the event of a tie, the biggest coin wins + 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_EQUAL(nValueRet, 11 * CENT); - BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // check that the smallest bigger coin is used add_coin( 1*COIN); @@ -164,12 +163,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) 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_EQUAL(nValueRet, 1 * COIN); // we should get 1 bitcoin in 1 coin - BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + 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_EQUAL(nValueRet, 2 * COIN); // we should get 2 bitcoins in 1 coin - BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance empty_wallet(); @@ -207,7 +206,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount - BOOST_CHECK_EQUAL(setCoinsRet.size(), 10); // in ten coins + BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins // if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0), // we need to try finding an exact subset anyway @@ -220,7 +219,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(1111 * CENT); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin - BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0) empty_wallet(); @@ -230,7 +229,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(1111 * CENT); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount - BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); // in two coins 0.4+0.6 + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6 // test avoiding sub-cent change empty_wallet(); @@ -241,12 +240,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // trying to make 1.0001 from these three coins BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins - BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01 - BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // test randomness { diff --git a/src/threadsafety.h b/src/threadsafety.h new file mode 100644 index 0000000..3d3d526 --- /dev/null +++ b/src/threadsafety.h @@ -0,0 +1,53 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_THREADSAFETY_H +#define BITCOIN_THREADSAFETY_H + +#ifdef __clang__ +// TL;DR Add GUARDED_BY(mutex) to member variables. The others are +// rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo); +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety +// for documentation. The clang compiler can do advanced static analysis +// of locking when given the -Wthread-safety option. +#define LOCKABLE __attribute__ ((lockable)) +#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable)) +#define GUARDED_BY(x) __attribute__ ((guarded_by(x))) +#define GUARDED_VAR __attribute__ ((guarded_var)) +#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x))) +#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var)) +#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__))) +#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__))) +#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__))) +#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__))) +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__))) +#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__))) +#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__))) +#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x))) +#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__))) +#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__ ((exclusive_locks_required(__VA_ARGS__))) +#define SHARED_LOCKS_REQUIRED(...) __attribute__ ((shared_locks_required(__VA_ARGS__))) +#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis)) +#else +#define LOCKABLE +#define SCOPED_LOCKABLE +#define GUARDED_BY(x) +#define GUARDED_VAR +#define PT_GUARDED_BY(x) +#define PT_GUARDED_VAR +#define ACQUIRED_AFTER(...) +#define ACQUIRED_BEFORE(...) +#define EXCLUSIVE_LOCK_FUNCTION(...) +#define SHARED_LOCK_FUNCTION(...) +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) +#define SHARED_TRYLOCK_FUNCTION(...) +#define UNLOCK_FUNCTION(...) +#define LOCK_RETURNED(x) +#define LOCKS_EXCLUDED(...) +#define EXCLUSIVE_LOCKS_REQUIRED(...) +#define SHARED_LOCKS_REQUIRED(...) +#define NO_THREAD_SAFETY_ANALYSIS +#endif // __GNUC__ +#endif // BITCOIN_THREADSAFETY_H diff --git a/src/txdb.cpp b/src/txdb.cpp new file mode 100644 index 0000000..3d34710 --- /dev/null +++ b/src/txdb.cpp @@ -0,0 +1,243 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "txdb.h" +#include "main.h" +#include "hash.h" + +using namespace std; + +void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) { + if (coins.IsPruned()) + batch.Erase(make_pair('c', hash)); + else + batch.Write(make_pair('c', hash), coins); +} + +void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { + batch.Write('B', hash); +} + +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { +} + +bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) { + return db.Read(make_pair('c', txid), coins); +} + +bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) { + CLevelDBBatch batch; + BatchWriteCoins(batch, txid, coins); + return db.WriteBatch(batch); +} + +bool CCoinsViewDB::HaveCoins(const uint256 &txid) { + return db.Exists(make_pair('c', txid)); +} + +CBlockIndex *CCoinsViewDB::GetBestBlock() { + uint256 hashBestChain; + if (!db.Read('B', hashBestChain)) + return NULL; + std::map::iterator it = mapBlockIndex.find(hashBestChain); + if (it == mapBlockIndex.end()) + return NULL; + return it->second; +} + +bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) { + CLevelDBBatch batch; + BatchWriteHashBestChain(batch, pindex->GetBlockHash()); + return db.WriteBatch(batch); +} + +bool CCoinsViewDB::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { + printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size()); + + CLevelDBBatch batch; + for (std::map::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) + BatchWriteCoins(batch, it->first, it->second); + if (pindex) + BatchWriteHashBestChain(batch, pindex->GetBlockHash()); + + return db.WriteBatch(batch); +} + +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { +} + +bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) +{ + return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); +} + +bool CBlockTreeDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork) +{ + return Read('I', bnBestInvalidWork); +} + +bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork) +{ + return Write('I', bnBestInvalidWork); +} + +bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) { + return Write(make_pair('f', nFile), info); +} + +bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { + return Read(make_pair('f', nFile), info); +} + +bool CBlockTreeDB::WriteLastBlockFile(int nFile) { + return Write('l', nFile); +} + +bool CBlockTreeDB::WriteReindexing(bool fReindexing) { + if (fReindexing) + return Write('R', '1'); + else + return Erase('R'); +} + +bool CBlockTreeDB::ReadReindexing(bool &fReindexing) { + fReindexing = Exists('R'); + return true; +} + +bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { + return Read('l', nFile); +} + +bool CCoinsViewDB::GetStats(CCoinsStats &stats) { + leveldb::Iterator *pcursor = db.NewIterator(); + pcursor->SeekToFirst(); + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + stats.hashBlock = GetBestBlock()->GetBlockHash(); + ss << stats.hashBlock; + int64 nTotalAmount = 0; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + leveldb::Slice slKey = pcursor->key(); + CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); + char chType; + ssKey >> chType; + if (chType == 'c') { + leveldb::Slice slValue = pcursor->value(); + CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); + CCoins coins; + ssValue >> coins; + uint256 txhash; + ssKey >> txhash; + ss << txhash; + ss << VARINT(coins.nVersion); + ss << (coins.fCoinBase ? 'c' : 'n'); + ss << VARINT(coins.nHeight); + stats.nTransactions++; + for (unsigned int i=0; iNext(); + } catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + delete pcursor; + stats.nHeight = GetBestBlock()->nHeight; + stats.hashSerialized = ss.GetHash(); + stats.nTotalAmount = nTotalAmount; + return true; +} + +bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { + return Read(make_pair('t', txid), pos); +} + +bool CBlockTreeDB::WriteTxIndex(const std::vector >&vect) { + CLevelDBBatch batch; + for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Write(make_pair('t', it->first), it->second); + return WriteBatch(batch); +} + +bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { + return Write(std::make_pair('F', name), fValue ? '1' : '0'); +} + +bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { + char ch; + if (!Read(std::make_pair('F', name), ch)) + return false; + fValue = ch == '1'; + return true; +} + +bool CBlockTreeDB::LoadBlockIndexGuts() +{ + leveldb::Iterator *pcursor = NewIterator(); + + CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); + ssKeySet << make_pair('b', uint256(0)); + pcursor->Seek(ssKeySet.str()); + + // Load mapBlockIndex + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + leveldb::Slice slKey = pcursor->key(); + CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); + char chType; + ssKey >> chType; + if (chType == 'b') { + leveldb::Slice slValue = pcursor->value(); + CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); + CDiskBlockIndex diskindex; + ssValue >> diskindex; + + // Construct block index object + CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + pindexNew->nHeight = diskindex.nHeight; + pindexNew->nFile = diskindex.nFile; + pindexNew->nDataPos = diskindex.nDataPos; + pindexNew->nUndoPos = diskindex.nUndoPos; + pindexNew->nVersion = diskindex.nVersion; + pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; + pindexNew->nTime = diskindex.nTime; + pindexNew->nBits = diskindex.nBits; + pindexNew->nNonce = diskindex.nNonce; + pindexNew->nStatus = diskindex.nStatus; + pindexNew->nTx = diskindex.nTx; + + // Watch for genesis block + if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) + pindexGenesisBlock = pindexNew; + + if (!pindexNew->CheckIndex()) + return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str()); + + pcursor->Next(); + } else { + break; // if shutdown requested or finished loading block index + } + } catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + delete pcursor; + + return true; +} diff --git a/src/txdb.h b/src/txdb.h new file mode 100644 index 0000000..f59fc5d --- /dev/null +++ b/src/txdb.h @@ -0,0 +1,53 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_TXDB_LEVELDB_H +#define BITCOIN_TXDB_LEVELDB_H + +#include "main.h" +#include "leveldb.h" + +/** CCoinsView backed by the LevelDB coin database (chainstate/) */ +class CCoinsViewDB : public CCoinsView +{ +protected: + CLevelDB db; +public: + CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); + + bool GetCoins(const uint256 &txid, CCoins &coins); + bool SetCoins(const uint256 &txid, const CCoins &coins); + bool HaveCoins(const uint256 &txid); + CBlockIndex *GetBestBlock(); + bool SetBestBlock(CBlockIndex *pindex); + bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); + bool GetStats(CCoinsStats &stats); +}; + +/** Access to the block database (blocks/index/) */ +class CBlockTreeDB : public CLevelDB +{ +public: + CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); +private: + CBlockTreeDB(const CBlockTreeDB&); + void operator=(const CBlockTreeDB&); +public: + bool WriteBlockIndex(const CDiskBlockIndex& blockindex); + bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork); + bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork); + bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo); + bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo); + bool ReadLastBlockFile(int &nFile); + bool WriteLastBlockFile(int nFile); + bool WriteReindexing(bool fReindex); + bool ReadReindexing(bool &fReindex); + bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); + bool WriteTxIndex(const std::vector > &list); + bool WriteFlag(const std::string &name, bool fValue); + bool ReadFlag(const std::string &name, bool &fValue); + bool LoadBlockIndexGuts(); +}; + +#endif // BITCOIN_TXDB_LEVELDB_H diff --git a/src/ui_interface.h b/src/ui_interface.h index 4775509..5b0555c 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -1,6 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2012 The Bitcoin developers -// Copyright (c) 2012 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UI_INTERFACE_H @@ -30,41 +29,49 @@ public: /** Flags for CClientUIInterface::ThreadSafeMessageBox */ enum MessageBoxFlags { - YES = 0x00000002, - OK = 0x00000004, - NO = 0x00000008, - YES_NO = (YES|NO), - CANCEL = 0x00000010, - APPLY = 0x00000020, - CLOSE = 0x00000040, - OK_DEFAULT = 0x00000000, - YES_DEFAULT = 0x00000000, - NO_DEFAULT = 0x00000080, - CANCEL_DEFAULT = 0x80000000, - ICON_EXCLAMATION = 0x00000100, - ICON_HAND = 0x00000200, - ICON_WARNING = ICON_EXCLAMATION, - ICON_ERROR = ICON_HAND, - ICON_QUESTION = 0x00000400, - ICON_INFORMATION = 0x00000800, - ICON_STOP = ICON_HAND, - ICON_ASTERISK = ICON_INFORMATION, - ICON_MASK = (0x00000100|0x00000200|0x00000400|0x00000800), - FORWARD = 0x00001000, - BACKWARD = 0x00002000, - RESET = 0x00004000, - HELP = 0x00008000, - MORE = 0x00010000, - SETUP = 0x00020000, - // Force blocking, modal message box dialog (not just OS notification) - MODAL = 0x00040000 + ICON_INFORMATION = 0, + ICON_WARNING = (1U << 0), + ICON_ERROR = (1U << 1), + /** + * Mask of all available icons in CClientUIInterface::MessageBoxFlags + * This needs to be updated, when icons are changed there! + */ + ICON_MASK = (ICON_INFORMATION | ICON_WARNING | ICON_ERROR), + + /** These values are taken from qmessagebox.h "enum StandardButton" to be directly usable */ + BTN_OK = 0x00000400U, // QMessageBox::Ok + BTN_YES = 0x00004000U, // QMessageBox::Yes + BTN_NO = 0x00010000U, // QMessageBox::No + BTN_ABORT = 0x00040000U, // QMessageBox::Abort + BTN_RETRY = 0x00080000U, // QMessageBox::Retry + BTN_IGNORE = 0x00100000U, // QMessageBox::Ignore + BTN_CLOSE = 0x00200000U, // QMessageBox::Close + BTN_CANCEL = 0x00400000U, // QMessageBox::Cancel + BTN_DISCARD = 0x00800000U, // QMessageBox::Discard + BTN_HELP = 0x01000000U, // QMessageBox::Help + BTN_APPLY = 0x02000000U, // QMessageBox::Apply + BTN_RESET = 0x04000000U, // QMessageBox::Reset + /** + * Mask of all available buttons in CClientUIInterface::MessageBoxFlags + * This needs to be updated, when buttons are changed there! + */ + BTN_MASK = (BTN_OK | BTN_YES | BTN_NO | BTN_ABORT | BTN_RETRY | BTN_IGNORE | + BTN_CLOSE | BTN_CANCEL | BTN_DISCARD | BTN_HELP | BTN_APPLY | BTN_RESET), + + /** Force blocking, modal message box dialog (not just OS notification) */ + MODAL = 0x10000000U, + + /** Predefined combinations for certain default usage cases */ + MSG_INFORMATION = ICON_INFORMATION, + MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL), + MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL) }; /** Show message box. */ - boost::signals2::signal ThreadSafeMessageBox; + boost::signals2::signal > ThreadSafeMessageBox; /** Ask the user whether they want to pay a fee or not. */ - boost::signals2::signal > ThreadSafeAskFee; + boost::signals2::signal > ThreadSafeAskFee; /** Handle a URL passed at the command line. */ boost::signals2::signal ThreadSafeHandleURI; @@ -72,9 +79,6 @@ public: /** Progress message during initialization. */ boost::signals2::signal InitMessage; - /** Initiate client shutdown. */ - boost::signals2::signal QueueShutdown; - /** Translate a message to the native language of the user. */ boost::signals2::signal Translate; diff --git a/src/uint256.h b/src/uint256.h index 45bea65..2a252c9 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UINT256_H @@ -10,6 +8,7 @@ #include #include #include +#include #include #include @@ -22,14 +21,14 @@ inline int Testuint256AdHoc(std::vector vArg); /** Base class without constructors for uint256 and uint160. - * This makes the compiler let u use it in a union. + * This makes the compiler let you use it in a union. */ template class base_uint { protected: enum { WIDTH=BITS/32 }; - unsigned int pn[WIDTH]; + uint32_t pn[WIDTH]; public: bool operator!() const @@ -57,6 +56,16 @@ public: return ret; } + double getdouble() const + { + double ret = 0.0; + double fact = 1.0; + for (int i = 0; i < WIDTH; i++) { + ret += fact * pn[i]; + fact *= 4294967296.0; + } + return ret; + } base_uint& operator=(uint64 b) { @@ -308,7 +317,7 @@ public: psz += 2; // hex string to uint - static unsigned char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,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,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + static const unsigned char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,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,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; const char* pbegin = psz; while (phexdigit[(unsigned char)*psz] || *psz == '0') psz++; @@ -346,7 +355,17 @@ public: return (unsigned char*)&pn[WIDTH]; } - unsigned int size() + const unsigned char* begin() const + { + return (unsigned char*)&pn[0]; + } + + const unsigned char* end() const + { + return (unsigned char*)&pn[WIDTH]; + } + + unsigned int size() const { return sizeof(pn); } diff --git a/src/util.cpp b/src/util.cpp index afb4f30..9fc4557 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,16 +1,25 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef WIN32 +// for posix_fallocate +#ifdef __linux__ +#define _POSIX_C_SOURCE 200112L +#endif +#include +#include +#include +#endif + #include "util.h" #include "sync.h" -#include "strlcpy.h" #include "version.h" #include "ui_interface.h" #include +#include // for to_lower() +#include // for startswith() and endswith() // 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 @@ -65,19 +74,19 @@ bool fDebug = false; bool fDebugNet = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; -bool fRequestShutdown = false; -bool fShutdown = false; bool fDaemon = false; bool fServer = false; bool fCommandLine = false; string strMiscWarning; bool fTestNet = false; +bool fBloomFilters = true; bool fNoListen = false; bool fLogTimestamps = false; CMedianFilter vTimeOffsets(200,0); -bool fReopenDebugLog = false; +volatile bool fReopenDebugLog = false; +bool fCachedPath[2] = {false, false}; -// Init openssl library multithreading support +// Init OpenSSL library multithreading support static CCriticalSection** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) { @@ -88,13 +97,15 @@ void locking_callback(int mode, int i, const char* file, int line) } } +LockedPageManager LockedPageManager::instance; + // Init class CInit { public: CInit() { - // Init openssl library multithreading support + // 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(); @@ -110,7 +121,7 @@ public: } ~CInit() { - // Shutdown openssl library multithreading support + // Shutdown OpenSSL library multithreading support CRYPTO_set_locking_callback(NULL); for (int i = 0; i < CRYPTO_num_locks(); i++) delete ppmutexOpenSSL[i]; @@ -155,8 +166,8 @@ void RandAddSeedPerfmon() if (ret == ERROR_SUCCESS) { RAND_add(pdata, nSize, nSize/100.0); - memset(pdata, 0, nSize); - printf("RandAddSeed() %d bytes\n", nSize); + OPENSSL_cleanse(pdata, nSize); + printf("RandAddSeed() %lu bytes\n", nSize); } #endif } @@ -194,56 +205,76 @@ uint256 GetRandHash() +// +// OutputDebugStringF (aka printf -- there is a #define that we really +// should get rid of one day) has been broken a couple of times now +// by well-meaning people adding mutexes in the most straightforward way. +// It breaks because it may be called by global destructors during shutdown. +// Since the order of destruction of static/global objects is undefined, +// defining a mutex as a global object doesn't work (the mutex gets +// destroyed, and then some later destructor calls OutputDebugStringF, +// maybe indirectly, and you get a core dump at shutdown trying to lock +// the mutex). -inline int OutputDebugStringF(const char* pszFormat, ...) +static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; +// We use boost::call_once() to make sure these are initialized in +// in a thread-safe manner the first time it is called: +static FILE* fileout = NULL; +static boost::mutex* mutexDebugLog = NULL; + +static void DebugPrintInit() { - int ret = 0; + assert(fileout == NULL); + assert(mutexDebugLog == NULL); + + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + fileout = fopen(pathDebug.string().c_str(), "a"); + if (fileout) setbuf(fileout, NULL); // unbuffered + + mutexDebugLog = new boost::mutex(); +} + +int OutputDebugStringF(const char* pszFormat, ...) +{ + int ret = 0; // Returns total number of characters written if (fPrintToConsole) { // print to console va_list arg_ptr; va_start(arg_ptr, pszFormat); - ret = vprintf(pszFormat, arg_ptr); + ret += vprintf(pszFormat, arg_ptr); va_end(arg_ptr); } - else + else if (!fPrintToDebugger) { - // print to debug.log - static FILE* fileout = NULL; + static bool fStartedNewLine = true; + boost::call_once(&DebugPrintInit, debugPrintInitFlag); - if (!fileout) - { + if (fileout == NULL) + return ret; + + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + + // reopen the log file, if requested + if (fReopenDebugLog) { + fReopenDebugLog = false; boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - fileout = fopen(pathDebug.string().c_str(), "a"); - if (fileout) setbuf(fileout, NULL); // unbuffered + if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) + setbuf(fileout, NULL); // unbuffered } - if (fileout) - { - static bool fStartedNewLine = true; - static boost::mutex mutexDebugLog; - boost::mutex::scoped_lock scoped_lock(mutexDebugLog); - // reopen the log file, if requested - if (fReopenDebugLog) { - fReopenDebugLog = false; - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) - setbuf(fileout, NULL); // unbuffered - } + // Debug print useful for profiling + if (fLogTimestamps && fStartedNewLine) + ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); + if (pszFormat[strlen(pszFormat) - 1] == '\n') + fStartedNewLine = true; + else + fStartedNewLine = false; - // Debug print useful for profiling - if (fLogTimestamps && fStartedNewLine) - fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); - if (pszFormat[strlen(pszFormat) - 1] == '\n') - fStartedNewLine = true; - else - fStartedNewLine = false; - - va_list arg_ptr; - va_start(arg_ptr, pszFormat); - ret = vfprintf(fileout, pszFormat, arg_ptr); - va_end(arg_ptr); - } + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + ret += vfprintf(fileout, pszFormat, arg_ptr); + va_end(arg_ptr); } #ifdef WIN32 @@ -266,6 +297,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...) { OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str()); line_start = line_end + 1; + ret += line_end-line_start; } buffer.erase(0, line_start); } @@ -274,7 +306,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...) return ret; } -string vstrprintf(const std::string &format, va_list ap) +string vstrprintf(const char *format, va_list ap) { char buffer[50000]; char* p = buffer; @@ -284,7 +316,11 @@ string vstrprintf(const std::string &format, va_list ap) { va_list arg_ptr; va_copy(arg_ptr, ap); - ret = _vsnprintf(p, limit, format.c_str(), arg_ptr); +#ifdef WIN32 + ret = _vsnprintf(p, limit, format, arg_ptr); +#else + ret = vsnprintf(p, limit, format, arg_ptr); +#endif va_end(arg_ptr); if (ret >= 0 && ret < limit) break; @@ -301,7 +337,7 @@ string vstrprintf(const std::string &format, va_list ap) return str; } -string real_strprintf(const std::string &format, int dummy, ...) +string real_strprintf(const char *format, int dummy, ...) { va_list arg_ptr; va_start(arg_ptr, dummy); @@ -310,6 +346,15 @@ string real_strprintf(const std::string &format, int dummy, ...) return str; } +string real_strprintf(const std::string &format, int dummy, ...) +{ + va_list arg_ptr; + va_start(arg_ptr, dummy); + string str = vstrprintf(format.c_str(), arg_ptr); + va_end(arg_ptr); + return str; +} + bool error(const char *format, ...) { va_list arg_ptr; @@ -350,7 +395,7 @@ string FormatMoney(int64 n, bool fPlus) int64 remainder = n_abs%COIN; string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder); - // Right-trim excess 0's before the decimal point: + // Right-trim excess zeros before the decimal point: int nTrim = 0; for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) ++nTrim; @@ -410,8 +455,21 @@ bool ParseMoney(const char* pszIn, int64& nRet) return true; } +// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything +// even possibly remotely dangerous like & or > +static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); +string SanitizeString(const string& str) +{ + string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (safeChars.find(str[i]) != std::string::npos) + strResult.push_back(str[i]); + } + return strResult; +} -static signed char phexdigit[256] = +static const signed char phexdigit[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -486,24 +544,24 @@ void ParseParameters(int argc, const char* const argv[]) mapMultiArgs.clear(); for (int i = 1; i < argc; i++) { - char psz[10000]; - strlcpy(psz, argv[i], sizeof(psz)); - char* pszValue = (char*)""; - if (strchr(psz, '=')) + std::string str(argv[i]); + std::string strValue; + size_t is_index = str.find('='); + if (is_index != std::string::npos) { - pszValue = strchr(psz, '='); - *pszValue++ = '\0'; + strValue = str.substr(is_index+1); + str = str.substr(0, is_index); } - #ifdef WIN32 - _strlwr(psz); - if (psz[0] == '/') - psz[0] = '-'; - #endif - if (psz[0] != '-') +#ifdef WIN32 + boost::to_lower(str); + if (boost::algorithm::starts_with(str, "/")) + str = "-" + str.substr(1); +#endif + if (str[0] != '-') break; - mapArgs[psz] = pszValue; - mapMultiArgs[psz].push_back(pszValue); + mapArgs[str] = strValue; + mapMultiArgs[str].push_back(strValue); } // New 0.6 features: @@ -973,10 +1031,10 @@ void PrintExceptionContinue(std::exception* pex, const char* pszThread) boost::filesystem::path GetDefaultDataDir() { namespace fs = boost::filesystem; - // Windows < Vista: C:\Documents and Settings\Username\Application Data\CasinoCoin - // Windows >= Vista: C:\Users\Username\AppData\Roaming\CasinoCoin - // Mac: ~/Library/Application Support/CasinoCoin - // Unix: ~/.casinocoin + // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin + // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin + // Mac: ~/Library/Application Support/Bitcoin + // Unix: ~/.bitcoin #ifdef WIN32 // Windows return GetSpecialFolderPath(CSIDL_APPDATA) / "CasinoCoin"; @@ -1005,13 +1063,12 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) static fs::path pathCached[2]; static CCriticalSection csPathCached; - static bool cachedPath[2] = {false, false}; fs::path &path = pathCached[fNetSpecific]; // This can be called during exceptions by printf, so we cache the // value so we don't have to do memory allocations after that. - if (cachedPath[fNetSpecific]) + if (fCachedPath[fNetSpecific]) return path; LOCK(csPathCached); @@ -1028,9 +1085,9 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) if (fNetSpecific && GetBoolArg("-testnet", false)) path /= "testnet3"; - fs::create_directory(path); + fs::create_directories(path); - cachedPath[fNetSpecific]=true; + fCachedPath[fNetSpecific] = true; return path; } @@ -1046,14 +1103,17 @@ void ReadConfigFile(map& mapSettingsRet, { boost::filesystem::ifstream streamConfig(GetConfigFile()); if (!streamConfig.good()) - return; // No casinocoin.conf file is OK + return; // No bitcoin.conf file is OK + + // clear path cache after loading config file + fCachedPath[0] = fCachedPath[1] = false; set 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 casinocoin.conf + // Don't overwrite existing settings so command line settings override bitcoin.conf string strKey = string("-") + it->string_key; if (mapSettingsRet.count(strKey) == 0) { @@ -1072,6 +1132,7 @@ boost::filesystem::path GetPidFile() return pathPidFile; } +#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { FILE* file = fopen(path.string().c_str(), "w"); @@ -1081,6 +1142,7 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid) fclose(file); } } +#endif bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) { @@ -1099,7 +1161,13 @@ void FileCommit(FILE *fileout) #ifdef WIN32 _commit(_fileno(fileout)); #else + #if defined(__linux__) || defined(__NetBSD__) + fdatasync(fileno(fileout)); + #elif defined(__APPLE__) && defined(F_FULLFSYNC) + fcntl(fileno(fileout), F_FULLFSYNC, 0); + #else fsync(fileno(fileout)); + #endif #endif } @@ -1113,6 +1181,80 @@ int GetFilesize(FILE* file) return nFilesize; } +bool TruncateFile(FILE *file, unsigned int length) { +#if defined(WIN32) + return _chsize(_fileno(file), length) == 0; +#else + return ftruncate(fileno(file), length) == 0; +#endif +} + + +// this function tries to raise the file descriptor limit to the requested number. +// It returns the actual file descriptor limit (which may be more or less than nMinFD) +int RaiseFileDescriptorLimit(int nMinFD) { +#if defined(WIN32) + return 2048; +#else + struct rlimit limitFD; + if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { + if (limitFD.rlim_cur < (rlim_t)nMinFD) { + limitFD.rlim_cur = nMinFD; + if (limitFD.rlim_cur > limitFD.rlim_max) + limitFD.rlim_cur = limitFD.rlim_max; + setrlimit(RLIMIT_NOFILE, &limitFD); + getrlimit(RLIMIT_NOFILE, &limitFD); + } + return limitFD.rlim_cur; + } + return nMinFD; // getrlimit failed, assume it's fine +#endif +} + +// this function tries to make a particular range of a file allocated (corresponding to disk space) +// it is advisory, and the range specified in the arguments will never contain live data +void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { +#if defined(WIN32) + // Windows-specific version + HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); + LARGE_INTEGER nFileSize; + int64 nEndPos = (int64)offset + length; + nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF; + nFileSize.u.HighPart = nEndPos >> 32; + SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN); + SetEndOfFile(hFile); +#elif defined(MAC_OSX) + // OSX specific version + fstore_t fst; + fst.fst_flags = F_ALLOCATECONTIG; + fst.fst_posmode = F_PEOFPOSMODE; + fst.fst_offset = 0; + fst.fst_length = (off_t)offset + length; + fst.fst_bytesalloc = 0; + if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) { + fst.fst_flags = F_ALLOCATEALL; + fcntl(fileno(file), F_PREALLOCATE, &fst); + } + ftruncate(fileno(file), fst.fst_length); +#elif defined(__linux__) + // Version using posix_fallocate + off_t nEndPos = (off_t)offset + length; + posix_fallocate(fileno(file), 0, nEndPos); +#else + // Fallback version + // TODO: just write one byte per block + static const char buf[65536] = {}; + fseek(file, offset, SEEK_SET); + while (length > 0) { + unsigned int now = 65536; + if (length < now) + now = length; + fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway + length -= now; + } +#endif +} + void ShrinkDebugFile() { // Scroll debug.log if it's getting too big @@ -1133,6 +1275,8 @@ void ShrinkDebugFile() fclose(file); } } + else if(file != NULL) + fclose(file); } @@ -1165,9 +1309,14 @@ void SetMockTime(int64 nMockTimeIn) static int64 nTimeOffset = 0; +int64 GetTimeOffset() +{ + return nTimeOffset; +} + int64 GetAdjustedTime() { - return GetTime() + nTimeOffset; + return GetTime() + GetTimeOffset(); } void AddTimeData(const CNetAddr& ip, int64 nTime) @@ -1207,10 +1356,10 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) if (!fMatch) { fDone = true; - string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong CasinoCoin will not work properly."); + string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong CasinoCoin will not work properly."); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - uiInterface.ThreadSafeMessageBox(strMessage+" ", string("CasinoCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } } } @@ -1223,12 +1372,26 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) } } - - - - - - +uint32_t insecure_rand_Rz = 11; +uint32_t insecure_rand_Rw = 11; +void seed_insecure_rand(bool fDeterministic) +{ + //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 { + RAND_bytes((unsigned char*)&tmp, 4); + } while(tmp == 0 || tmp == 0x9068ffffU); + insecure_rand_Rz = tmp; + do { + RAND_bytes((unsigned char*)&tmp, 4); + } while(tmp == 0 || tmp == 0x464fffffU); + insecure_rand_Rw = tmp; + } +} string FormatVersion(int nVersion) { @@ -1272,6 +1435,28 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif +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)) { + printf("GetTempPath(): failed to find temp path\n"); + return boost::filesystem::path(""); + } + return path; +#endif +} + void runCommand(std::string strCommand) { int nErr = ::system(strCommand.c_str()); @@ -1302,3 +1487,15 @@ void RenameThread(const char* name) (void)name; #endif } + +bool NewThread(void(*pfn)(void*), void* parg) +{ + try + { + boost::thread(pfn, parg); // thread detaches when out of scope + } catch(boost::thread_resource_error &e) { + printf("Error creating thread: %s\n", e.what()); + return false; + } + return true; +} diff --git a/src/util.h b/src/util.h index 2f145ea..42f5a7c 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UTIL_H @@ -9,26 +7,26 @@ #include "uint256.h" +#include + #ifndef WIN32 #include #include #include -#else -typedef int pid_t; /* define for windows compatiblity */ #endif #include +#include +#include #include #include +#include #include #include #include #include #include -#include -#include - #include "netbase.h" // for AddTimeData typedef long long int64; @@ -43,7 +41,6 @@ static const int64 CENT = 1000000; #define UBEGIN(a) ((unsigned char*)&(a)) #define UEND(a) ((unsigned char*)&((&(a))[1])) #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) -#define printf OutputDebugStringF #ifndef PRI64d #if defined(_MSC_VER) || defined(__MSVCRT__) @@ -57,6 +54,26 @@ static const int64 CENT = 1000000; #endif #endif +/* Format characters for (s)size_t and ptrdiff_t */ +#if defined(_MSC_VER) || defined(__MSVCRT__) + /* (s)size_t and ptrdiff_t have the same size specifier in MSVC: + http://msdn.microsoft.com/en-us/library/tcxf1dw6%28v=vs.100%29.aspx + */ + #define PRIszx "Ix" + #define PRIszu "Iu" + #define PRIszd "Id" + #define PRIpdx "Ix" + #define PRIpdu "Iu" + #define PRIpdd "Id" +#else /* C99 standard */ + #define PRIszx "zx" + #define PRIszu "zu" + #define PRIszd "zd" + #define PRIpdx "tx" + #define PRIpdu "tu" + #define PRIpdd "td" +#endif + // This is needed because the foreach macro can't get over the comma in pair #define PAIRTYPE(t1, t2) std::pair @@ -82,20 +99,32 @@ T* alignup(T* p) #define S_IRUSR 0400 #define S_IWUSR 0200 #endif -#define unlink _unlink #else -#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) -#define strlwr(psz) to_lower(psz) -#define _strlwr(psz) to_lower(psz) #define MAX_PATH 1024 -inline void Sleep(int64 n) -{ - /*Boost has a year 2038 problem— if the request sleep time is past epoch+2^31 seconds the sleep returns instantly. - So we clamp our sleeps here to 10 years and hope that boost is fixed by 2028.*/ - boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n>315576000000LL?315576000000LL:n)); -} #endif +inline void MilliSleep(int64 n) +{ +// Boost's sleep_for was uninterruptable 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 + +#if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200) + boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); +#else + boost::this_thread::sleep(boost::posix_time::milliseconds(n)); +#endif +} + +/* This GNU C extension enables the compiler to check the format string against the parameters provided. + * X is the number of the "format string" parameter, and Y is the number of the first variadic parameter. + * Parameters count from 1. + */ +#ifdef __GNUC__ +#define ATTR_WARN_PRINTF(X,Y) __attribute__((format(printf,X,Y))) +#else +#define ATTR_WARN_PRINTF(X,Y) +#endif @@ -110,31 +139,46 @@ extern bool fDebug; extern bool fDebugNet; extern bool fPrintToConsole; extern bool fPrintToDebugger; -extern bool fRequestShutdown; -extern bool fShutdown; extern bool fDaemon; extern bool fServer; extern bool fCommandLine; extern std::string strMiscWarning; extern bool fTestNet; +extern bool fBloomFilters; extern bool fNoListen; extern bool fLogTimestamps; -extern bool fReopenDebugLog; +extern volatile bool fReopenDebugLog; void RandAddSeed(); void RandAddSeedPerfmon(); -int OutputDebugStringF(const char* pszFormat, ...); -int my_snprintf(char* buffer, size_t limit, const char* format, ...); +int ATTR_WARN_PRINTF(1,2) OutputDebugStringF(const char* pszFormat, ...); -/* It is not allowed to use va_start with a pass-by-reference argument. - (C++ standard, 18.7, paragraph 3). Use a dummy argument to work around this, and use a - macro to keep similar semantics. +/* + Rationale for the real_strprintf / strprintf construction: + It is not allowed to use va_start with a pass-by-reference argument. + (C++ standard, 18.7, paragraph 3). Use a dummy argument to work around this, and use a + macro to keep similar semantics. */ + +/** Overload strprintf for char*, so that GCC format type warnings can be given */ +std::string ATTR_WARN_PRINTF(1,3) real_strprintf(const char *format, int dummy, ...); +/** Overload strprintf for std::string, to be able to use it with _ (translation). + * This will not support GCC format type warnings (-Wformat) so be careful. + */ std::string real_strprintf(const std::string &format, int dummy, ...); #define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__) -std::string vstrprintf(const std::string &format, va_list ap); +std::string vstrprintf(const char *format, va_list ap); + +bool ATTR_WARN_PRINTF(1,2) error(const char *format, ...); + +/* Redefine printf so that it directs output to debug.log + * + * Do this *after* defining the other printf-like functions, because otherwise the + * __attribute__((format(printf,X,Y))) gets expanded to __attribute__((format(OutputDebugStringF,X,Y))) + * which confuses gcc. + */ +#define printf OutputDebugStringF -bool error(const char *format, ...); void LogException(std::exception* pex, const char* pszThread); void PrintException(std::exception* pex, const char* pszThread); void PrintExceptionContinue(std::exception* pex, const char* pszThread); @@ -142,6 +186,7 @@ void ParseString(const std::string& str, char c, std::vector& v); std::string FormatMoney(int64 n, bool fPlus=false); bool ParseMoney(const std::string& str, int64& nRet); bool ParseMoney(const char* pszIn, int64& nRet); +std::string SanitizeString(const std::string& str); std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); bool IsHex(const std::string& str); @@ -158,16 +203,22 @@ bool WildcardMatch(const char* psz, const char* mask); bool WildcardMatch(const std::string& str, const std::string& mask); void FileCommit(FILE *fileout); int GetFilesize(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); boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); boost::filesystem::path GetConfigFile(); boost::filesystem::path GetPidFile(); +#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid); +#endif void ReadConfigFile(std::map& mapSettingsRet, std::map >& mapMultiSettingsRet); #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif +boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); @@ -175,6 +226,7 @@ uint256 GetRandHash(); int64 GetTime(); void SetMockTime(int64 nMockTimeIn); int64 GetAdjustedTime(); +int64 GetTimeOffset(); std::string FormatFullVersion(); std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments); void AddTimeData(const CNetAddr& ip, int64 nTime); @@ -239,9 +291,9 @@ inline int64 abs64(int64 n) template std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) { - std::vector rv; - static char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; rv.reserve((itend-itbegin)*3); for(T it = itbegin; it < itend; ++it) { @@ -252,10 +304,11 @@ std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) rv.push_back(hexmap[val&15]); } - return std::string(rv.begin(), rv.end()); + return rv; } -inline std::string HexStr(const std::vector& vch, bool fSpaces=false) +template +inline std::string HexStr(const T& vch, bool fSpaces=false) { return HexStr(vch.begin(), vch.end(), fSpaces); } @@ -290,6 +343,12 @@ inline int64 GetTimeMillis() boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); } +inline int64 GetTimeMicros() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); +} + inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime) { time_t n = nTime; @@ -360,132 +419,44 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue); */ bool SoftSetBoolArg(const std::string& strArg, bool fValue); - - - - - - - - -// Randomize the stack to help protect against buffer overrun exploits -#define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \ - { \ - static char nLoops; \ - if (nLoops <= 0) \ - nLoops = GetRand(20) + 1; \ - if (nLoops-- > 1) \ - { \ - ThreadFn; \ - return; \ - } \ - } - - -template -inline uint256 Hash(const T1 pbegin, const T1 pend) +/** + * 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 + */ +extern uint32_t insecure_rand_Rz; +extern uint32_t insecure_rand_Rw; +static inline uint32_t insecure_rand(void) { - static unsigned char pblank[1]; - uint256 hash1; - SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; + 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; } -class CHashWriter +/** + * Seed insecure_rand using the random pool. + * @param Deterministic Use a determinstic seed + */ +void seed_insecure_rand(bool fDeterministic=false); + +/** + * Timing-attack-resistant comparison. + * Takes time proportional to length + * of first argument. + */ +template +bool TimingResistantEqual(const T& a, const T& b) { -private: - SHA256_CTX ctx; - -public: - int nType; - int nVersion; - - void Init() { - SHA256_Init(&ctx); - } - - CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) { - Init(); - } - - CHashWriter& write(const char *pch, size_t size) { - SHA256_Update(&ctx, pch, size); - return (*this); - } - - // invalidates the object - uint256 GetHash() { - uint256 hash1; - SHA256_Final((unsigned char*)&hash1, &ctx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; - } - - template - CHashWriter& operator<<(const T& obj) { - // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } -}; - - -template -inline uint256 Hash(const T1 p1begin, const T1 p1end, - const T2 p2begin, const T2 p2end) -{ - static unsigned char pblank[1]; - uint256 hash1; - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); - SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); - SHA256_Final((unsigned char*)&hash1, &ctx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; + if (b.size() == 0) return a.size() == 0; + size_t accumulator = a.size() ^ b.size(); + for (size_t i = 0; i < a.size(); i++) + accumulator |= a[i] ^ b[i%b.size()]; + return accumulator == 0; } -template -inline uint256 Hash(const T1 p1begin, const T1 p1end, - const T2 p2begin, const T2 p2end, - const T3 p3begin, const T3 p3end) -{ - static unsigned char pblank[1]; - uint256 hash1; - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); - SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); - SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0])); - SHA256_Final((unsigned char*)&hash1, &ctx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; -} - -template -uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) -{ - CHashWriter ss(nType, nVersion); - ss << obj; - return ss.GetHash(); -} - -inline uint160 Hash160(const std::vector& vch) -{ - uint256 hash1; - SHA256(&vch[0], vch.size(), (unsigned char*)&hash1); - uint160 hash2; - RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; -} - - -/** Median filter over a stream of values. +/** Median filter over a stream of values. * Returns the median of the last N numbers */ template class CMedianFilter @@ -502,7 +473,7 @@ public: vValues.push_back(initial_value); vSorted = vValues; } - + void input(T value) { if(vValues.size() == nSize) @@ -541,65 +512,14 @@ public: } }; +bool NewThread(void(*pfn)(void*), void* parg); - - - - - - - - -// Note: It turns out we might have been able to use boost::thread -// by using TerminateThread(boost::thread.native_handle(), 0); #ifdef WIN32 -typedef HANDLE pthread_t; - -inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false) -{ - DWORD nUnused = 0; - HANDLE hthread = - CreateThread( - NULL, // default security - 0, // inherit stack size from parent - (LPTHREAD_START_ROUTINE)pfn, // function pointer - parg, // argument - 0, // creation option, start immediately - &nUnused); // thread identifier - if (hthread == NULL) - { - printf("Error: CreateThread() returned %d\n", GetLastError()); - return (pthread_t)0; - } - if (!fWantHandle) - { - CloseHandle(hthread); - return (pthread_t)-1; - } - return hthread; -} - inline void SetThreadPriority(int nPriority) { SetThreadPriority(GetCurrentThread(), nPriority); } #else -inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false) -{ - pthread_t hthread = 0; - int ret = pthread_create(&hthread, NULL, (void*(*)(void*))pfn, parg); - if (ret != 0) - { - printf("Error: pthread_create() returned %d\n", ret); - return (pthread_t)0; - } - if (!fWantHandle) - { - pthread_detach(hthread); - return (pthread_t)-1; - } - return hthread; -} #define THREAD_PRIORITY_LOWEST PRIO_MAX #define THREAD_PRIORITY_BELOW_NORMAL 2 @@ -631,5 +551,60 @@ inline uint32_t ByteReverse(uint32_t value) return (value<<16) | (value>>16); } -#endif +// Standard wrapper for do-something-forever thread functions. +// "Forever" really means until the thread is interrupted. +// Use it like: +// new boost::thread(boost::bind(&LoopForever, "dumpaddr", &DumpAddresses, 900000)); +// or maybe: +// boost::function f = boost::bind(&FunctionWithArg, argument); +// threadGroup.create_thread(boost::bind(&LoopForever >, "nothing", f, milliseconds)); +template void LoopForever(const char* name, Callable func, int64 msecs) +{ + std::string s = strprintf("bitcoin-%s", name); + RenameThread(s.c_str()); + printf("%s thread start\n", name); + try + { + while (1) + { + MilliSleep(msecs); + func(); + } + } + catch (boost::thread_interrupted) + { + printf("%s thread stop\n", name); + throw; + } + catch (std::exception& e) { + PrintException(&e, name); + } + catch (...) { + PrintException(NULL, name); + } +} +// .. and a wrapper that just calls func once +template void TraceThread(const char* name, Callable func) +{ + std::string s = strprintf("bitcoin-%s", name); + RenameThread(s.c_str()); + try + { + printf("%s thread start\n", name); + func(); + printf("%s thread exit\n", name); + } + catch (boost::thread_interrupted) + { + printf("%s thread interrupt\n", name); + throw; + } + catch (std::exception& e) { + PrintException(&e, name); + } + catch (...) { + PrintException(NULL, name); + } +} +#endif diff --git a/src/version.cpp b/src/version.cpp index 5bba575..c8c86d2 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -1,5 +1,4 @@ // Copyright (c) 2012 The Bitcoin developers -// Copyright (c) 2012 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include @@ -41,13 +40,11 @@ const std::string CLIENT_NAME("transcoder"); # define GIT_COMMIT_DATE "" #endif -#define STRINGIFY(s) #s - #define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \ - "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-g" commit + "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit #define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \ - "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-unk" + "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk" #ifndef BUILD_DESC # ifdef GIT_COMMIT_ID diff --git a/src/version.h b/src/version.h index 9935a0c..01dfbba 100644 --- a/src/version.h +++ b/src/version.h @@ -1,25 +1,19 @@ // Copyright (c) 2012 The Bitcoin developers -// Copyright (c) 2012 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_VERSION_H #define BITCOIN_VERSION_H +#include "clientversion.h" #include // // client versioning // -// These need to be macro's, as version.cpp's voodoo requires it -#define CLIENT_VERSION_MAJOR 1 -#define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 4 - static const int CLIENT_VERSION = 1000000 * CLIENT_VERSION_MAJOR - + 10000 * CLIENT_VERSION_MINOR + + 10000 * CLIENT_VERSION_MINOR + 100 * CLIENT_VERSION_REVISION + 1 * CLIENT_VERSION_BUILD; @@ -31,10 +25,13 @@ extern const std::string CLIENT_DATE; // network protocol versioning // -static const int PROTOCOL_VERSION = 60002; +static const int PROTOCOL_VERSION = 70002; -// earlier versions not supported as of Feb 2012, and are disconnected -static const int MIN_PROTO_VERSION = 209; +// intial proto version, to be increased after version/verack negotiation +static const int INIT_PROTO_VERSION = 209; + +// disconnect from peers older than this proto version +static const int MIN_PEER_PROTO_VERSION = 60002; // nTime field added to CAddress, starting with this version; // if possible, avoid requesting addresses nodes older than this @@ -47,4 +44,7 @@ static const int NOBLKS_VERSION_END = 32400; // BIP 0031, pong message, is enabled for all versions AFTER this one static const int BIP0031_VERSION = 60000; +// "mempool" command, enhanced "getdata" behavior starts with this version: +static const int MEMPOOL_GD_VERSION = 60002; + #endif diff --git a/src/wallet.cpp b/src/wallet.cpp index 9857d79..f9ffd8e 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,6 +8,8 @@ #include "crypter.h" #include "ui_interface.h" #include "base58.h" +#include "coincontrol.h" +#include using namespace std; @@ -33,26 +33,28 @@ CPubKey CWallet::GenerateNewKey() bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets RandAddSeedPerfmon(); - CKey key; - key.MakeNewKey(fCompressed); + CKey secret; + secret.MakeNewKey(fCompressed); // Compressed public keys were introduced in version 0.6.0 if (fCompressed) SetMinVersion(FEATURE_COMPRPUBKEY); - if (!AddKey(key)) + CPubKey pubkey = secret.GetPubKey(); + if (!AddKeyPubKey(secret, pubkey)) throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); - return key.GetPubKey(); + return pubkey; } -bool CWallet::AddKey(const CKey& key) +bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) { - if (!CCryptoKeyStore::AddKey(key)) + if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) return false; if (!fFileBacked) return true; - if (!IsCrypted()) - return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); + if (!IsCrypted()) { + return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey()); + } return true; } @@ -72,6 +74,11 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector &vchCryptedSecret) +{ + return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); +} + bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) @@ -293,6 +300,41 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } +int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb) +{ + int64 nRet = nOrderPosNext++; + if (pwalletdb) { + pwalletdb->WriteOrderPosNext(nOrderPosNext); + } else { + CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); + } + return nRet; +} + +CWallet::TxItems CWallet::OrderedTxItems(std::list& acentries, std::string strAccount) +{ + CWalletDB walletdb(strWalletFile); + + // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. + TxItems txOrdered; + + // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry + // would make this much faster for applications that do this a lot. + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx* wtx = &((*it).second); + txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); + } + acentries.clear(); + walletdb.ListAccountCreditDebit(strAccount, acentries); + BOOST_FOREACH(CAccountingEntry& entry, acentries) + { + txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + } + + return txOrdered; +} + void CWallet::WalletUpdateSpent(const CTransaction &tx) { // Anytime a signature is successfully verified, it's proof the outpoint is spent. @@ -306,7 +348,9 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) if (mi != mapWallet.end()) { CWalletTx& wtx = (*mi).second; - if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) + if (txin.prevout.n >= wtx.vout.size()) + printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); + else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) { printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkSpent(txin.prevout.n); @@ -338,7 +382,56 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) wtx.BindWallet(this); bool fInsertedNew = ret.second; if (fInsertedNew) + { wtx.nTimeReceived = GetAdjustedTime(); + wtx.nOrderPos = IncOrderPosNext(); + + wtx.nTimeSmart = wtx.nTimeReceived; + if (wtxIn.hashBlock != 0) + { + if (mapBlockIndex.count(wtxIn.hashBlock)) + { + unsigned int latestNow = wtx.nTimeReceived; + unsigned int latestEntry = 0; + { + // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future + int64 latestTolerated = latestNow + 300; + std::list acentries; + TxItems txOrdered = OrderedTxItems(acentries); + for (TxItems::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 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; + } + } + } + + unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime; + wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); + } + else + printf("AddToWallet() : found %s in block %s not in index\n", + wtxIn.GetHash().ToString().c_str(), + wtxIn.hashBlock.ToString().c_str()); + } + } bool fUpdated = false; if (!fInsertedNew) @@ -364,7 +457,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) } //// debug print - printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); + printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); // Write to disk if (fInsertedNew || fUpdated) @@ -372,17 +465,19 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) return false; #ifndef QT_GUI // If default receiving address gets used, replace it with a new one - CScript scriptDefaultKey; - scriptDefaultKey.SetDestination(vchDefaultKey.GetID()); - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - { - if (txout.scriptPubKey == scriptDefaultKey) + if (vchDefaultKey.IsValid()) { + CScript scriptDefaultKey; + scriptDefaultKey.SetDestination(vchDefaultKey.GetID()); + BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - CPubKey newDefaultKey; - if (GetKeyFromPool(newDefaultKey, false)) + if (txout.scriptPubKey == scriptDefaultKey) { - SetDefaultKey(newDefaultKey); - SetAddressBookName(vchDefaultKey.GetID(), ""); + CPubKey newDefaultKey; + if (GetKeyFromPool(newDefaultKey, false)) + { + SetDefaultKey(newDefaultKey); + SetAddressBookName(vchDefaultKey.GetID(), ""); + } } } } @@ -392,6 +487,16 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // 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", ""); + + if ( !strCmd.empty()) + { + boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free + } + } return true; } @@ -399,9 +504,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) +bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) { - uint256 hash = tx.GetHash(); { LOCK(cs_wallet); bool fExisted = mapWallet.count(hash); @@ -487,7 +591,8 @@ bool CWallet::IsChange(const CTxOut& txout) const int64 CWalletTx::GetTxTime() const { - return nTimeReceived; + int64 n = nTimeSmart; + return n ? n : nTimeReceived; } int CWalletTx::GetRequestCount() const @@ -529,23 +634,14 @@ int CWalletTx::GetRequestCount() const return nRequests; } -void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list >& listReceived, +void CWalletTx::GetAmounts(list >& listReceived, list >& listSent, int64& nFee, string& strSentAccount) const { - nGeneratedImmature = nGeneratedMature = nFee = 0; + nFee = 0; listReceived.clear(); listSent.clear(); strSentAccount = strFromAccount; - if (IsCoinBase()) - { - if (GetBlocksToMaturity() > 0) - nGeneratedImmature = pwallet->GetCredit(*this); - else - nGeneratedMature = GetCredit(); - return; - } - // Compute fee: int64 nDebit = GetDebit(); if (nDebit > 0) // debit>0 means we signed/sent this transaction @@ -578,20 +674,17 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l } -void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, +void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nReceived, int64& nSent, int64& nFee) const { - nGenerated = nReceived = nSent = nFee = 0; + nReceived = nSent = nFee = 0; - int64 allGeneratedImmature, allGeneratedMature, allFee; - allGeneratedImmature = allGeneratedMature = allFee = 0; + int64 allFee; string strSentAccount; list > listReceived; list > listSent; - GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); + GetAmounts(listReceived, listSent, allFee, strSentAccount); - if (strAccount == "") - nGenerated = allGeneratedMature; if (strAccount == strSentAccount) { BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& s, listSent) @@ -616,7 +709,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i } } -void CWalletTx::AddSupportingTransactions(CTxDB& txdb) +void CWalletTx::AddSupportingTransactions() { vtxPrev.clear(); @@ -627,7 +720,6 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) BOOST_FOREACH(const CTxIn& txin, vin) vWorkQueue.push_back(txin.prevout.hash); - // This critsect is OK because txdb is already open { LOCK(pwallet->cs_wallet); map mapWalletPrev; @@ -651,13 +743,8 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) { tx = *mapWalletPrev[hash]; } - else if (!fClient && txdb.ReadDiskTx(hash, tx)) - { - ; - } else { - printf("ERROR: AddSupportingTransactions() : unsupported transaction\n"); continue; } @@ -694,10 +781,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) while (pindex) { CBlock block; - block.ReadFromDisk(pindex, true); + block.ReadFromDisk(pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { - if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) + if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) ret++; } pindex = pindex->pnext; @@ -706,49 +793,35 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) return ret; } -int CWallet::ScanForWalletTransaction(const uint256& hashTx) -{ - CTransaction tx; - tx.ReadFromDisk(COutPoint(hashTx, 0)); - if (AddToWalletIfInvolvingMe(tx, NULL, true, true)) - return 1; - return 0; -} - void CWallet::ReacceptWalletTransactions() { - CTxDB txdb("r"); bool fRepeat = true; while (fRepeat) { LOCK(cs_wallet); fRepeat = false; - vector vMissingTx; + bool fMissing = false; BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { CWalletTx& wtx = item.second; if (wtx.IsCoinBase() && wtx.IsSpent(0)) continue; - CTxIndex txindex; + CCoins coins; bool fUpdated = false; - if (txdb.ReadTxIndex(wtx.GetHash(), txindex)) + bool fFound = pcoinsTip->GetCoins(wtx.GetHash(), coins); + if (fFound || wtx.GetDepthInMainChain() > 0) { // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat - if (txindex.vSpent.size() != wtx.vout.size()) - { - printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size()); - continue; - } - for (unsigned int i = 0; i < txindex.vSpent.size(); i++) + for (unsigned int i = 0; i < wtx.vout.size(); i++) { if (wtx.IsSpent(i)) continue; - if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i])) + if ((i >= coins.vout.size() || coins.vout[i].IsNull()) && IsMine(wtx.vout[i])) { wtx.MarkSpent(i); fUpdated = true; - vMissingTx.push_back(txindex.vSpent[i]); + fMissing = true; } } if (fUpdated) @@ -760,46 +833,39 @@ void CWallet::ReacceptWalletTransactions() } else { - // Reaccept any txes of ours that aren't already in a block + // Re-accept any txes of ours that aren't already in a block if (!wtx.IsCoinBase()) - wtx.AcceptWalletTransaction(txdb, false); + wtx.AcceptWalletTransaction(false); } } - if (!vMissingTx.empty()) + if (fMissing) { // TODO: optimize this to scan just part of the block chain? if (ScanForWalletTransactions(pindexGenesisBlock)) - fRepeat = true; // Found missing transactions: re-do Reaccept. - } - } -} - -void CWalletTx::RelayWalletTransaction(CTxDB& txdb) -{ - BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) - { - if (!tx.IsCoinBase()) - { - uint256 hash = tx.GetHash(); - if (!txdb.ContainsTx(hash)) - RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx); - } - } - if (!IsCoinBase()) - { - uint256 hash = GetHash(); - if (!txdb.ContainsTx(hash)) - { - printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str()); - RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this); + fRepeat = true; // Found missing transactions: re-do re-accept. } } } void CWalletTx::RelayWalletTransaction() { - CTxDB txdb("r"); - RelayWalletTransaction(txdb); + BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) + { + // Important: versions of bitcoin before 0.8.6 had a bug that inserted + // empty transactions into the vtxPrev, which will cause the node to be + // banned when retransmitted, hence the check for !tx.vin.empty() + if (!tx.IsCoinBase() && !tx.vin.empty()) + if (tx.GetDepthInMainChain() == 0) + RelayTransaction((CTransaction)tx, tx.GetHash()); + } + if (!IsCoinBase()) + { + if (GetDepthInMainChain() == 0) { + uint256 hash = GetHash(); + printf("Relaying wtx %s\n", hash.ToString().c_str()); + RelayTransaction((CTransaction)*this, hash); + } + } } void CWallet::ResendWalletTransactions() @@ -822,7 +888,6 @@ void CWallet::ResendWalletTransactions() // Rebroadcast any of our txes that aren't in a block yet printf("ResendWalletTransactions()\n"); - CTxDB txdb("r"); { LOCK(cs_wallet); // Sort them in chronological order @@ -838,7 +903,7 @@ void CWallet::ResendWalletTransactions() BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { CWalletTx& wtx = *item.second; - wtx.RelayWalletTransaction(txdb); + wtx.RelayWalletTransaction(); } } } @@ -862,7 +927,7 @@ int64 CWallet::GetBalance() const for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (pcoin->IsFinal() && pcoin->IsConfirmed()) + if (pcoin->IsConfirmed()) nTotal += pcoin->GetAvailableCredit(); } } @@ -892,16 +957,15 @@ int64 CWallet::GetImmatureBalance() const LOCK(cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx& pcoin = (*it).second; - if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.GetDepthInMainChain() >= 2) - nTotal += GetCredit(pcoin); + const CWalletTx* pcoin = &(*it).second; + nTotal += pcoin->GetImmatureCredit(); } } return nTotal; } // populate vCoins with vector of spendable COutputs -void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed) const +void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const { vCoins.clear(); @@ -920,11 +984,12 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed) const if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; - // If output is less than minimum value, then don't include transaction. - // This is to help deal with dust spam clogging up create transactions. - for (unsigned int i = 0; i < pcoin->vout.size(); i++) - if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue >= nMinimumInputValue) - vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { + if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && + !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue >= nMinimumInputValue && + (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i))) + vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + } } } } @@ -937,6 +1002,8 @@ static void ApproximateBestSubset(vector >& setCoinsRet, int64& nValueRet) const +bool CWallet::SelectCoins(int64 nTargetValue, set >& setCoinsRet, int64& nValueRet, const CCoinControl* coinControl) const { vector vCoins; - AvailableCoins(vCoins); + AvailableCoins(vCoins, true, coinControl); + + // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) + if (coinControl && coinControl->HasSelected()) + { + BOOST_FOREACH(const COutput& out, vCoins) + { + nValueRet += out.tx->vout[out.i].nValue; + setCoinsRet.insert(make_pair(out.tx, out.i)); + } + return (nValueRet >= nTargetValue); + } return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || @@ -1079,24 +1163,29 @@ bool CWallet::SelectCoins(int64 nTargetValue, set >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(const vector >& vecSend, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl) { int64 nValue = 0; BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) { if (nValue < 0) + { + strFailReason = _("Transaction amounts must be positive"); return false; + } nValue += s.second; } if (vecSend.empty() || nValue < 0) + { + strFailReason = _("Transaction amounts must be positive"); return false; + } wtxNew.BindWallet(this); { LOCK2(cs_main, cs_wallet); - // txdb must be opened before the mapWallet lock - CTxDB txdb("r"); { nFeeRet = nTransactionFee; loop @@ -1109,52 +1198,87 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW double dPriority = 0; // vouts to the payees BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) - wtxNew.vout.push_back(CTxOut(s.second, s.first)); + { + CTxOut txout(s.second, s.first); + if (txout.IsDust()) + { + strFailReason = _("Transaction amount too small"); + return false; + } + wtxNew.vout.push_back(txout); + } // Choose coins to use set > setCoins; int64 nValueIn = 0; - if (!SelectCoins(nTotalValue, setCoins, nValueIn)) + if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl)) + { + strFailReason = _("Insufficient funds"); return false; + } BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { int64 nCredit = pcoin.first->vout[pcoin.second].nValue; - dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); + //The priority 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. + dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1); } int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE + // if sub-cent change is required, the fee must be raised to at least nMinTxFee // or until nChange becomes zero // NOTE: this depends on the exact behaviour of GetMinFee - if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT) + if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) { - int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet); + int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); nChange -= nMoveToFee; nFeeRet += nMoveToFee; } if (nChange > 0) { - // Note: We use a new key here to keep it from being obvious which side is the change. - // The drawback is that by not reusing a previous key, the change may be lost if a - // backup is restored, if the backup doesn't have the new private key for the change. - // If we reused the old key, it would be possible to add code to look for and - // rediscover unknown transactions that were written with keys of ours to recover - // post-backup change. - - // Reserve a new key pair from key pool - CPubKey vchPubKey = reservekey.GetReservedKey(); - // assert(mapKeys.count(vchPubKey)); - // Fill a vout to ourself // TODO: pass in scriptChange instead of reservekey so // change transaction isn't always pay-to-bitcoin-address CScript scriptChange; - scriptChange.SetDestination(vchPubKey.GetID()); + + // coin control: send change to custom address + if (coinControl && !boost::get(&coinControl->destChange)) + scriptChange.SetDestination(coinControl->destChange); + + // no coin control: send change to newly generated address + else + { + // Note: We use a new key here to keep it from being obvious which side is the change. + // The drawback is that by not reusing a previous key, the change may be lost if a + // backup is restored, if the backup doesn't have the new private key for the change. + // If we reused the old key, it would be possible to add code to look for and + // rediscover unknown transactions that were written with keys of ours to recover + // post-backup change. - // Insert change txn at random position: - vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()); - wtxNew.vout.insert(position, CTxOut(nChange, scriptChange)); + // Reserve a new key pair from key pool + CPubKey vchPubKey; + assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked + + scriptChange.SetDestination(vchPubKey.GetID()); + } + + CTxOut newTxOut(nChange, scriptChange); + + // Never create dust outputs; if we would, just + // add the dust to the fee. + if (newTxOut.IsDust()) + { + nFeeRet += nChange; + reservekey.ReturnKey(); + } + else + { + // Insert change txn at random position: + vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); + wtxNew.vout.insert(position, newTxOut); + } } else reservekey.ReturnKey(); @@ -1167,12 +1291,18 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW int nIn = 0; BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) + { + strFailReason = _("Signing transaction failed"); return false; + } // Limit size unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); - if (nBytes >= MAX_BLOCK_SIZE_GEN/5) + if (nBytes >= MAX_STANDARD_TX_SIZE) + { + strFailReason = _("Transaction too large"); return false; + } dPriority /= nBytes; // Check that enough fee is included @@ -1186,7 +1316,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW } // Fill vtxPrev by copying from previous transactions vtxPrev - wtxNew.AddSupportingTransactions(txdb); + wtxNew.AddSupportingTransactions(); wtxNew.fTimeReceivedIsTxTime = true; break; @@ -1196,11 +1326,12 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW return true; } -bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl) { vector< pair > vecSend; vecSend.push_back(make_pair(scriptPubKey, nValue)); - return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet); + return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason, coinControl); } // Call after CreateTransaction unless you want to abort @@ -1241,7 +1372,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) mapRequestCount[wtxNew.GetHash()] = 0; // Broadcast - if (!wtxNew.AcceptToMemoryPool()) + if (!wtxNew.AcceptToMemoryPool(true, false)) { // This must not fail. The transaction has already been signed and recorded. printf("CommitTransaction() : Error: Transaction not valid"); @@ -1262,26 +1393,24 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, if (IsLocked()) { - string strError = _("Error: Wallet locked, unable to create transaction "); + string strError = _("Error: Wallet locked, unable to create transaction!"); printf("SendMoney() : %s", strError.c_str()); return strError; } - if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) + string strError; + if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError)) { - string strError; if (nValue + nFeeRequired > 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).c_str()); - else - strError = _("Error: Transaction creation failed "); - printf("SendMoney() : %s", strError.c_str()); + 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).c_str()); + printf("SendMoney() : %s\n", strError.c_str()); return strError; } - if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending..."))) + if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired)) return "ABORTED"; if (!CommitTransaction(wtxNew, reservekey)) - return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); return ""; } @@ -1306,12 +1435,12 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64 nVal -int CWallet::LoadWallet(bool& fFirstRunRet) +DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) - return false; + return DB_LOAD_OK; fFirstRunRet = false; - int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); + DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) @@ -1321,14 +1450,12 @@ int CWallet::LoadWallet(bool& fFirstRunRet) // User will be prompted to unlock wallet the next operation // the requires a new key. } - nLoadWalletRet = DB_NEED_REWRITE; } if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; fFirstRunRet = !vchDefaultKey.IsValid(); - CreateThread(ThreadFlushWalletDB, &strWalletFile); return DB_LOAD_OK; } @@ -1360,7 +1487,7 @@ void CWallet::PrintWallet(const CBlock& block) if (mapWallet.count(block.vtx[0].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + printf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } } printf("\n"); @@ -1447,7 +1574,7 @@ bool CWallet::TopUpKeyPool() if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); - printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size()); + printf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size()); } } return true; @@ -1551,7 +1678,139 @@ int64 CWallet::GetOldestKeyPoolTime() return keypool.nTime; } -CPubKey CReserveKey::GetReservedKey() +std::map CWallet::GetAddressBalances() +{ + map balances; + + { + LOCK(cs_wallet); + BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) + { + CWalletTx *pcoin = &walletEntry.second; + + if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) + continue; + + if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + continue; + + int nDepth = pcoin->GetDepthInMainChain(); + if (nDepth < (pcoin->IsFromMe() ? 0 : 1)) + continue; + + for (unsigned int i = 0; i < pcoin->vout.size(); i++) + { + CTxDestination addr; + if (!IsMine(pcoin->vout[i])) + continue; + if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr)) + continue; + + int64 n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue; + + if (!balances.count(addr)) + balances[addr] = 0; + balances[addr] += n; + } + } + } + + return balances; +} + +set< set > CWallet::GetAddressGroupings() +{ + set< set > groupings; + set grouping; + + BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) + { + CWalletTx *pcoin = &walletEntry.second; + + if (pcoin->vin.size() > 0) + { + bool any_mine = false; + // group all input addresses with each other + BOOST_FOREACH(CTxIn txin, pcoin->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)) + continue; + grouping.insert(address); + any_mine = true; + } + + // group change with input addresses + if (any_mine) + { + BOOST_FOREACH(CTxOut txout, pcoin->vout) + if (IsChange(txout)) + { + CTxDestination txoutAddr; + if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) + continue; + grouping.insert(txoutAddr); + } + } + if (grouping.size() > 0) + { + groupings.insert(grouping); + grouping.clear(); + } + } + + // group lone addrs by themselves + for (unsigned int i = 0; i < pcoin->vout.size(); i++) + if (IsMine(pcoin->vout[i])) + { + CTxDestination address; + if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address)) + continue; + grouping.insert(address); + groupings.insert(grouping); + grouping.clear(); + } + } + + set< set* > uniqueGroupings; // a set of pointers to groups of addresses + map< CTxDestination, set* > setmap; // map addresses to the unique group containing it + BOOST_FOREACH(set grouping, groupings) + { + // make a set of all the groups hit by this new group + set< set* > hits; + map< CTxDestination, set* >::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* merged = new set(grouping); + BOOST_FOREACH(set* hit, hits) + { + merged->insert(hit->begin(), hit->end()); + uniqueGroupings.erase(hit); + delete hit; + } + uniqueGroupings.insert(merged); + + // update setmap + BOOST_FOREACH(CTxDestination element, *merged) + setmap[element] = merged; + } + + set< set > ret; + BOOST_FOREACH(set* uniqueGrouping, uniqueGroupings) + { + ret.insert(*uniqueGrouping); + delete uniqueGrouping; + } + + return ret; +} + +bool CReserveKey::GetReservedKey(CPubKey& pubkey) { if (nIndex == -1) { @@ -1559,14 +1818,17 @@ CPubKey CReserveKey::GetReservedKey() pwallet->ReserveKeyFromKeyPool(nIndex, keypool); if (nIndex != -1) vchPubKey = keypool.vchPubKey; - else - { - printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool."); - vchPubKey = pwallet->vchDefaultKey; + else { + if (pwallet->vchDefaultKey.IsValid()) { + printf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!"); + vchPubKey = pwallet->vchDefaultKey; + } else + return false; } } assert(vchPubKey.IsValid()); - return vchPubKey; + pubkey = vchPubKey; + return true; } void CReserveKey::KeepKey() @@ -1615,3 +1877,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } + +void CWallet::LockCoin(COutPoint& output) +{ + setLockedCoins.insert(output); +} + +void CWallet::UnlockCoin(COutPoint& output) +{ + setLockedCoins.erase(output); +} + +void CWallet::UnlockAllCoins() +{ + setLockedCoins.clear(); +} + +bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const +{ + COutPoint outpt(hash, n); + + return (setLockedCoins.count(outpt) > 0); +} + +void CWallet::ListLockedCoins(std::vector& vOutpts) +{ + for (std::set::iterator it = setLockedCoins.begin(); + it != setLockedCoins.end(); it++) { + COutPoint outpt = (*it); + vOutpts.push_back(outpt); + } +} + diff --git a/src/wallet.h b/src/wallet.h index 864ea5c..cd1fb34 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -1,22 +1,28 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_H #define BITCOIN_WALLET_H +#include +#include + +#include + #include "main.h" #include "key.h" #include "keystore.h" #include "script.h" #include "ui_interface.h" +#include "util.h" +#include "walletdb.h" +class CAccountingEntry; class CWalletTx; class CReserveKey; -class CWalletDB; class COutput; +class CCoinControl; /** (client) version numbers for particular wallet features */ enum WalletFeature @@ -63,7 +69,7 @@ public: class CWallet : public CCryptoKeyStore { private: - bool SelectCoins(int64 nTargetValue, std::set >& setCoinsRet, int64& nValueRet) const; + bool SelectCoins(int64 nTargetValue, std::set >& setCoinsRet, int64& nValueRet, const CCoinControl *coinControl=NULL) const; CWalletDB *pwalletdbEncryption; @@ -93,6 +99,7 @@ public: fFileBacked = false; nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; + nOrderPosNext = 0; } CWallet(std::string strWalletFileIn) { @@ -102,35 +109,44 @@ public: fFileBacked = true; nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; + nOrderPosNext = 0; } std::map mapWallet; + int64 nOrderPosNext; std::map mapRequestCount; std::map mapAddressBook; CPubKey vchDefaultKey; + std::set setLockedCoins; + // check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } - void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true) const; + void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl=NULL) const; bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64& nValueRet) const; + bool IsLockedCoin(uint256 hash, unsigned int n) const; + void LockCoin(COutPoint& output); + void UnlockCoin(COutPoint& output); + void UnlockAllCoins(); + void ListLockedCoins(std::vector& vOutpts); // keystore implementation // Generate a new key CPubKey GenerateNewKey(); // Adds a key to the store, and saves it to disk. - bool AddKey(const CKey& key); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); // Adds a key to the store, without saving it to disk (used by LoadWallet) - bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } + bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } // Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } + bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); bool AddCScript(const CScript& redeemScript); bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); } @@ -138,20 +154,35 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); + /** Increment the next transaction order id + @return next transaction order id + */ + int64 IncOrderPosNext(CWalletDB *pwalletdb = NULL); + + typedef std::pair TxPair; + typedef std::multimap TxItems; + + /** Get the wallet's activity log + @return multimap of ordered transactions and accounting entries + @warning Returned pointers are *only* valid within the scope of passed acentries + */ + TxItems OrderedTxItems(std::list& acentries, std::string strAccount = ""); + void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn); - bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); + bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); bool EraseFromWallet(uint256 hash); void WalletUpdateSpent(const CTransaction& prevout); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); - int ScanForWalletTransaction(const uint256& hashTx); void ReacceptWalletTransactions(); void ResendWalletTransactions(); int64 GetBalance() const; int64 GetUnconfirmedBalance() const; int64 GetImmatureBalance() const; - bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); - bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); + bool CreateTransaction(const std::vector >& vecSend, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl=NULL); + bool CreateTransaction(CScript scriptPubKey, int64 nValue, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl=NULL); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); std::string SendMoneyToDestination(const CTxDestination &address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); @@ -166,6 +197,9 @@ public: int64 GetOldestKeyPoolTime(); void GetAllReserveKeys(std::set& setAddress); + std::set< std::set > GetAddressGroupings(); + std::map GetAddressBalances(); + bool IsMine(const CTxIn& txin) const; int64 GetDebit(const CTxIn& txin) const; bool IsMine(const CTxOut& txout) const @@ -188,8 +222,6 @@ public: bool IsMine(const CTransaction& tx) const { BOOST_FOREACH(const CTxOut& txout, tx.vout) - // If output is less than minimum value, then don't include transaction. - // This is to help deal with dust spam bloating the wallet. if (IsMine(txout) && txout.nValue >= nMinimumInputValue) return true; return false; @@ -233,7 +265,7 @@ public: } void SetBestChain(const CBlockLocator& loc); - int LoadWallet(bool& fFirstRunRet); + DBErrors LoadWallet(bool& fFirstRunRet); bool SetAddressBookName(const CTxDestination& address, const std::string& strName); @@ -298,17 +330,38 @@ public: ~CReserveKey() { - if (!fShutdown) - ReturnKey(); + ReturnKey(); } void ReturnKey(); - CPubKey GetReservedKey(); + bool GetReservedKey(CPubKey &pubkey); void KeepKey(); }; -/** A transaction with a bunch of additional info that only the owner cares about. +typedef std::map mapValue_t; + + +static void ReadOrderPos(int64& nOrderPos, mapValue_t& mapValue) +{ + if (!mapValue.count("n")) + { + nOrderPos = -1; // TODO: calculate elsewhere + return; + } + nOrderPos = atoi64(mapValue["n"].c_str()); +} + + +static void WriteOrderPos(const int64& nOrderPos, mapValue_t& mapValue) +{ + if (nOrderPos == -1) + return; + mapValue["n"] = i64tostr(nOrderPos); +} + + +/** A transaction with a bunch of additional info that only the owner cares about. * It includes any unrecorded transactions needed to link it back to the block chain. */ class CWalletTx : public CMerkleTx @@ -318,21 +371,25 @@ private: public: std::vector vtxPrev; - std::map mapValue; + mapValue_t mapValue; std::vector > vOrderForm; unsigned int fTimeReceivedIsTxTime; unsigned int nTimeReceived; // time received by this node + unsigned int nTimeSmart; char fFromMe; std::string strFromAccount; std::vector vfSpent; // which outputs are already spent + int64 nOrderPos; // position in ordered transaction list // memory only mutable bool fDebitCached; mutable bool fCreditCached; + mutable bool fImmatureCreditCached; mutable bool fAvailableCreditCached; mutable bool fChangeCached; mutable int64 nDebitCached; mutable int64 nCreditCached; + mutable int64 nImmatureCreditCached; mutable int64 nAvailableCreditCached; mutable int64 nChangeCached; @@ -364,17 +421,21 @@ public: vOrderForm.clear(); fTimeReceivedIsTxTime = false; nTimeReceived = 0; + nTimeSmart = 0; fFromMe = false; strFromAccount.clear(); vfSpent.clear(); fDebitCached = false; fCreditCached = false; + fImmatureCreditCached = false; fAvailableCreditCached = false; fChangeCached = false; nDebitCached = 0; nCreditCached = 0; + nImmatureCreditCached = 0; nAvailableCreditCached = 0; nChangeCached = 0; + nOrderPos = -1; } IMPLEMENT_SERIALIZE @@ -396,6 +457,11 @@ public: fSpent = true; } pthis->mapValue["spent"] = str; + + WriteOrderPos(pthis->nOrderPos, pthis->mapValue); + + if (nTimeSmart) + pthis->mapValue["timesmart"] = strprintf("%u", nTimeSmart); } nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); @@ -416,11 +482,17 @@ public: pthis->vfSpent.push_back(c != '0'); else pthis->vfSpent.assign(vout.size(), fSpent); + + ReadOrderPos(pthis->nOrderPos, pthis->mapValue); + + pthis->nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(pthis->mapValue["timesmart"]) : 0; } pthis->mapValue.erase("fromaccount"); pthis->mapValue.erase("version"); pthis->mapValue.erase("spent"); + pthis->mapValue.erase("n"); + pthis->mapValue.erase("timesmart"); ) // marks certain txout's as spent @@ -504,6 +576,20 @@ public: return nCreditCached; } + int64 GetImmatureCredit(bool fUseCache=true) const + { + if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) + { + if (fUseCache && fImmatureCreditCached) + return nImmatureCreditCached; + nImmatureCreditCached = pwallet->GetCredit(*this); + fImmatureCreditCached = true; + return nImmatureCreditCached; + } + + return 0; + } + int64 GetAvailableCredit(bool fUseCache=true) const { // Must wait until coinbase is safely deep enough in the chain before valuing it @@ -540,10 +626,10 @@ public: return nChangeCached; } - void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list >& listReceived, + void GetAmounts(std::list >& listReceived, std::list >& listSent, int64& nFee, std::string& strSentAccount) const; - void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, + void GetAccountAmounts(const std::string& strAccount, int64& nReceived, int64& nSent, int64& nFee) const; bool IsFromMe() const @@ -599,12 +685,8 @@ public: int64 GetTxTime() const; int GetRequestCount() const; - void AddSupportingTransactions(CTxDB& txdb); - - bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true); - bool AcceptWalletTransaction(); - - void RelayWalletTransaction(CTxDB& txdb); + void AddSupportingTransactions(); + bool AcceptWalletTransaction(bool fCheckInputs=true); void RelayWalletTransaction(); }; @@ -625,7 +707,7 @@ public: std::string ToString() const { - return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString().substr(0,10).c_str(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); + return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString().c_str(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); } void print() const @@ -709,6 +791,9 @@ public: int64 nTime; std::string strOtherAccount; std::string strComment; + mapValue_t mapValue; + int64 nOrderPos; // position in ordered transaction list + uint64 nEntryNo; CAccountingEntry() { @@ -722,18 +807,55 @@ public: strAccount.clear(); strOtherAccount.clear(); strComment.clear(); + nOrderPos = -1; } IMPLEMENT_SERIALIZE ( + CAccountingEntry& me = *const_cast(this); if (!(nType & SER_GETHASH)) READWRITE(nVersion); // Note: strAccount is serialized as part of the key, not here. READWRITE(nCreditDebit); READWRITE(nTime); READWRITE(strOtherAccount); + + if (!fRead) + { + WriteOrderPos(nOrderPos, me.mapValue); + + if (!(mapValue.empty() && _ssExtra.empty())) + { + CDataStream ss(nType, nVersion); + ss.insert(ss.begin(), '\0'); + ss << mapValue; + ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); + me.strComment.append(ss.str()); + } + } + READWRITE(strComment); + + size_t nSepPos = strComment.find("\0", 0, 1); + if (fRead) + { + me.mapValue.clear(); + if (std::string::npos != nSepPos) + { + CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); + ss >> me.mapValue; + me._ssExtra = std::vector(ss.begin(), ss.end()); + } + ReadOrderPos(me.nOrderPos, me.mapValue); + } + if (std::string::npos != nSepPos) + me.strComment.erase(nSepPos); + + me.mapValue.erase("n"); ) + +private: + std::vector _ssExtra; }; bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index d2cb906..cdc692f 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -1,12 +1,11 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "walletdb.h" #include "wallet.h" +#include #include using namespace std; @@ -44,9 +43,14 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) return Write(make_pair(string("acc"), strAccount), account); } +bool CWalletDB::WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry& acentry) +{ + return Write(boost::make_tuple(string("acentry"), acentry.strAccount, nAccEntryNum), acentry); +} + bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) { - return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry); + return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) @@ -97,6 +101,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list> acentry; + ssKey >> acentry.nEntryNo; entries.push_back(acentry); } @@ -104,15 +109,276 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, listcs_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 TxPair; + typedef multimap TxItems; + TxItems txByTime; + + for (map::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 acentries; + ListAccountCreditDebit("", acentries); + BOOST_FOREACH(CAccountingEntry& entry, acentries) + { + txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); + } + + int64& nOrderPosNext = pwallet->nOrderPosNext; + nOrderPosNext = 0; + std::vector nOrderPosOffsets; + for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) + { + CWalletTx *const pwtx = (*it).second.first; + CAccountingEntry *const pacentry = (*it).second.second; + int64& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos; + + if (nOrderPos == -1) + { + nOrderPos = nOrderPosNext++; + nOrderPosOffsets.push_back(nOrderPos); + + if (pacentry) + // Have to write accounting regardless, since we don't keep it in memory + if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) + return DB_LOAD_FAIL; + } + else + { + int64 nOrderPosOff = 0; + BOOST_FOREACH(const int64& 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->GetHash(), *pwtx)) + return DB_LOAD_FAIL; + } + else + if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) + return DB_LOAD_FAIL; + } + } + + return DB_LOAD_OK; +} + + +bool +ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, + int& nFileVersion, vector& vWalletUpgrade, + bool& fIsEncrypted, bool& fAnyUnordered, string& strType, string& strErr) +{ + try { + // Unserialize + // Taking advantage of the fact that pair serialization + // is just the two items serialized one after the other + ssKey >> strType; + if (strType == "name") + { + string strAddress; + ssKey >> strAddress; + ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()]; + } + else if (strType == "tx") + { + uint256 hash; + ssKey >> hash; + CWalletTx& wtx = pwallet->mapWallet[hash]; + ssValue >> wtx; + CValidationState state; + if (wtx.CheckTransaction(state) && (wtx.GetHash() == hash) && state.IsValid()) + wtx.BindWallet(pwallet); + else + { + pwallet->mapWallet.erase(hash); + return false; + } + + // Undo serialize changes in 31600 + if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) + { + if (!ssValue.empty()) + { + char fTmp; + char fUnused; + ssValue >> fTmp >> fUnused >> wtx.strFromAccount; + strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s", + wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str()); + wtx.fTimeReceivedIsTxTime = fTmp; + } + else + { + strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str()); + wtx.fTimeReceivedIsTxTime = 0; + } + vWalletUpgrade.push_back(hash); + } + + if (wtx.nOrderPos == -1) + fAnyUnordered = true; + + //// debug print + //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); + //printf(" %12"PRI64d" %s %s %s\n", + // wtx.vout[0].nValue, + // DateTimeStrFormat("%Y-%m-%d %H:%M:%S", wtx.GetBlockTime()).c_str(), + // wtx.hashBlock.ToString().c_str(), + // wtx.mapValue["message"].c_str()); + } + else if (strType == "acentry") + { + string strAccount; + ssKey >> strAccount; + uint64 nNumber; + ssKey >> nNumber; + if (nNumber > nAccountingEntryNumber) + nAccountingEntryNumber = nNumber; + + if (!fAnyUnordered) + { + CAccountingEntry acentry; + ssValue >> acentry; + if (acentry.nOrderPos == -1) + fAnyUnordered = true; + } + } + else if (strType == "key" || strType == "wkey") + { + CPubKey vchPubKey; + ssKey >> vchPubKey; + if (!vchPubKey.IsValid()) + { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } + CKey key; + CPrivKey pkey; + if (strType == "key") + ssValue >> pkey; + else { + CWalletKey wkey; + ssValue >> wkey; + pkey = wkey.vchPrivKey; + } + if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed())) + { + strErr = "Error reading wallet database: CPrivKey corrupt"; + return false; + } + if (key.GetPubKey() != vchPubKey) + { + strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; + return false; + } + if (!pwallet->LoadKey(key, vchPubKey)) + { + strErr = "Error reading wallet database: LoadKey failed"; + return false; + } + } + else if (strType == "mkey") + { + unsigned int nID; + ssKey >> nID; + CMasterKey kMasterKey; + ssValue >> kMasterKey; + if(pwallet->mapMasterKeys.count(nID) != 0) + { + strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID); + return false; + } + pwallet->mapMasterKeys[nID] = kMasterKey; + if (pwallet->nMasterKeyMaxID < nID) + pwallet->nMasterKeyMaxID = nID; + } + else if (strType == "ckey") + { + vector vchPubKey; + ssKey >> vchPubKey; + vector vchPrivKey; + ssValue >> vchPrivKey; + if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) + { + strErr = "Error reading wallet database: LoadCryptedKey failed"; + return false; + } + fIsEncrypted = true; + } + else if (strType == "defaultkey") + { + ssValue >> pwallet->vchDefaultKey; + } + else if (strType == "pool") + { + int64 nIndex; + ssKey >> nIndex; + pwallet->setKeyPool.insert(nIndex); + } + else if (strType == "version") + { + ssValue >> nFileVersion; + if (nFileVersion == 10300) + nFileVersion = 300; + } + else if (strType == "cscript") + { + uint160 hash; + ssKey >> hash; + CScript script; + ssValue >> script; + if (!pwallet->LoadCScript(script)) + { + strErr = "Error reading wallet database: LoadCScript failed"; + return false; + } + } + else if (strType == "orderposnext") + { + ssValue >> pwallet->nOrderPosNext; + } + } catch (...) + { + return false; + } + return true; +} + +static bool IsKeyType(string strType) +{ + return (strType== "key" || strType == "wkey" || + strType == "mkey" || strType == "ckey"); +} + +DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { pwallet->vchDefaultKey = CPubKey(); int nFileVersion = 0; vector vWalletUpgrade; bool fIsEncrypted = false; + bool fAnyUnordered = false; + bool fNoncriticalErrors = false; + DBErrors result = DB_LOAD_OK; - //// todo: shouldn't we catch exceptions and try to recover and continue? - { + try { LOCK(pwallet->cs_wallet); int nMinVersion = 0; if (Read((string)"minversion", nMinVersion)) @@ -144,174 +410,48 @@ int CWalletDB::LoadWallet(CWallet* pwallet) return DB_CORRUPT; } - // Unserialize - // Taking advantage of the fact that pair serialization - // is just the two items serialized one after the other - string strType; - ssKey >> strType; - if (strType == "name") + // Try to be tolerant of single corrupt records: + string strType, strErr; + if (!ReadKeyValue(pwallet, ssKey, ssValue, nFileVersion, + vWalletUpgrade, fIsEncrypted, fAnyUnordered, strType, strErr)) { - string strAddress; - ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()]; - } - else if (strType == "tx") - { - uint256 hash; - ssKey >> hash; - CWalletTx& wtx = pwallet->mapWallet[hash]; - ssValue >> wtx; - wtx.BindWallet(pwallet); - - if (wtx.GetHash() != hash) - printf("Error in wallet.dat, hash mismatch\n"); - - // Undo serialize changes in 31600 - if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) - { - if (!ssValue.empty()) - { - char fTmp; - char fUnused; - ssValue >> fTmp >> fUnused >> wtx.strFromAccount; - printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str()); - wtx.fTimeReceivedIsTxTime = fTmp; - } - else - { - printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str()); - wtx.fTimeReceivedIsTxTime = 0; - } - vWalletUpgrade.push_back(hash); - } - - //// debug print - //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); - //printf(" %12"PRI64d" %s %s %s\n", - // wtx.vout[0].nValue, - // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(), - // wtx.hashBlock.ToString().substr(0,20).c_str(), - // wtx.mapValue["message"].c_str()); - } - else if (strType == "acentry") - { - string strAccount; - ssKey >> strAccount; - uint64 nNumber; - ssKey >> nNumber; - if (nNumber > nAccountingEntryNumber) - nAccountingEntryNumber = nNumber; - } - else if (strType == "key" || strType == "wkey") - { - vector vchPubKey; - ssKey >> vchPubKey; - CKey key; - if (strType == "key") - { - CPrivKey pkey; - ssValue >> pkey; - key.SetPubKey(vchPubKey); - key.SetPrivKey(pkey); - if (key.GetPubKey() != vchPubKey) - { - printf("Error reading wallet database: CPrivKey pubkey inconsistency\n"); - return DB_CORRUPT; - } - if (!key.IsValid()) - { - printf("Error reading wallet database: invalid CPrivKey\n"); - return DB_CORRUPT; - } - } + // losing keys is considered a catastrophic error, anything else + // we assume the user can live with: + if (IsKeyType(strType)) + result = DB_CORRUPT; else { - CWalletKey wkey; - ssValue >> wkey; - key.SetPubKey(vchPubKey); - key.SetPrivKey(wkey.vchPrivKey); - if (key.GetPubKey() != vchPubKey) - { - printf("Error reading wallet database: CWalletKey pubkey inconsistency\n"); - return DB_CORRUPT; - } - if (!key.IsValid()) - { - printf("Error reading wallet database: invalid CWalletKey\n"); - return DB_CORRUPT; - } - } - if (!pwallet->LoadKey(key)) - { - printf("Error reading wallet database: LoadKey failed\n"); - return DB_CORRUPT; - } - } - else if (strType == "mkey") - { - unsigned int nID; - ssKey >> nID; - CMasterKey kMasterKey; - ssValue >> kMasterKey; - if(pwallet->mapMasterKeys.count(nID) != 0) - { - printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID); - return DB_CORRUPT; - } - pwallet->mapMasterKeys[nID] = kMasterKey; - if (pwallet->nMasterKeyMaxID < nID) - pwallet->nMasterKeyMaxID = nID; - } - else if (strType == "ckey") - { - vector vchPubKey; - ssKey >> vchPubKey; - vector vchPrivKey; - ssValue >> vchPrivKey; - if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) - { - printf("Error reading wallet database: LoadCryptedKey failed\n"); - return DB_CORRUPT; - } - fIsEncrypted = true; - } - else if (strType == "defaultkey") - { - ssValue >> pwallet->vchDefaultKey; - } - else if (strType == "pool") - { - int64 nIndex; - ssKey >> nIndex; - pwallet->setKeyPool.insert(nIndex); - } - else if (strType == "version") - { - ssValue >> nFileVersion; - if (nFileVersion == 10300) - nFileVersion = 300; - } - else if (strType == "cscript") - { - uint160 hash; - ssKey >> hash; - CScript script; - ssValue >> script; - if (!pwallet->LoadCScript(script)) - { - printf("Error reading wallet database: LoadCScript failed\n"); - return DB_CORRUPT; + // Leave other errors alone, if we try to fix them we might make things worse. + fNoncriticalErrors = true; // ... but do warn the user there is something wrong. + if (strType == "tx") + // Rescan if there is a bad transaction record: + SoftSetBoolArg("-rescan", true); } } + if (!strErr.empty()) + printf("%s\n", strErr.c_str()); } pcursor->close(); } + catch (boost::thread_interrupted) { + throw; + } + catch (...) { + result = DB_CORRUPT; + } - BOOST_FOREACH(uint256 hash, vWalletUpgrade) - WriteTx(hash, pwallet->mapWallet[hash]); + if (fNoncriticalErrors && result == DB_LOAD_OK) + result = DB_NONCRITICAL_ERROR; + + // Any wallet corruption at all: skip any rewriting or + // upgrading, we don't want to make it worse. + if (result != DB_LOAD_OK) + return result; printf("nFileVersion = %d\n", nFileVersion); + BOOST_FOREACH(uint256 hash, vWalletUpgrade) + WriteTx(hash, pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) @@ -320,15 +460,17 @@ int CWalletDB::LoadWallet(CWallet* pwallet) if (nFileVersion < CLIENT_VERSION) // Update WriteVersion(CLIENT_VERSION); - return DB_LOAD_OK; + if (fAnyUnordered) + result = ReorderTransactions(pwallet); + + return result; } -void ThreadFlushWalletDB(void* parg) +void ThreadFlushWalletDB(const string& strFile) { // Make this thread recognisable as the wallet flushing thread RenameThread("bitcoin-wallet"); - const string& strFile = ((const string*)parg)[0]; static bool fOneThread; if (fOneThread) return; @@ -339,9 +481,9 @@ void ThreadFlushWalletDB(void* parg) unsigned int nLastSeen = nWalletDBUpdated; unsigned int nLastFlushed = nWalletDBUpdated; int64 nLastWalletUpdate = GetTime(); - while (!fShutdown) + while (true) { - Sleep(500); + MilliSleep(500); if (nLastSeen != nWalletDBUpdated) { @@ -363,8 +505,9 @@ void ThreadFlushWalletDB(void* parg) mi++; } - if (nRefCount == 0 && !fShutdown) + if (nRefCount == 0) { + boost::this_thread::interruption_point(); map::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { @@ -389,7 +532,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) { if (!wallet.fFileBacked) return false; - while (!fShutdown) + while (true) { { LOCK(bitdb.cs_db); @@ -420,7 +563,98 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) } } } - Sleep(100); + MilliSleep(100); } return false; } + +// +// Try to (very carefully!) recover wallet.dat if there is a problem. +// +bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) +{ + // Recovery procedure: + // move wallet.dat to wallet.timestamp.bak + // Call Salvage with fAggressive=true to + // get as much data as possible. + // Rewrite salvaged data to wallet.dat + // Set -rescan so any missing transactions will be + // found. + int64 now = GetTime(); + std::string newFilename = strprintf("wallet.%"PRI64d".bak", now); + + int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL, + newFilename.c_str(), DB_AUTO_COMMIT); + if (result == 0) + printf("Renamed %s to %s\n", filename.c_str(), newFilename.c_str()); + else + { + printf("Failed to rename %s to %s\n", filename.c_str(), newFilename.c_str()); + return false; + } + + std::vector salvagedData; + bool allOK = dbenv.Salvage(newFilename, true, salvagedData); + if (salvagedData.empty()) + { + printf("Salvage(aggressive) found no records in %s.\n", newFilename.c_str()); + return false; + } + printf("Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size()); + + bool fSuccess = allOK; + 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) + { + printf("Cannot create database file %s\n", filename.c_str()); + return false; + } + CWallet dummyWallet; + int nFileVersion = 0; + vector vWalletUpgrade; + bool fIsEncrypted = false; + bool fAnyUnordered = false; + + 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 = ReadKeyValue(&dummyWallet, ssKey, ssValue, + nFileVersion, vWalletUpgrade, + fIsEncrypted, fAnyUnordered, + strType, strErr); + if (!IsKeyType(strType)) + continue; + if (!fReadOK) + { + printf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType.c_str(), strErr.c_str()); + 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); + delete pdbCopy; + + return fSuccess; +} + +bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename) +{ + return CWalletDB::Recover(dbenv, filename, false); +} diff --git a/src/walletdb.h b/src/walletdb.h index 296326b..8ae6c3f 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 Litecoin Developers -// Copyright (c) 2013 CasinoCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLETDB_H @@ -19,6 +17,7 @@ enum DBErrors { DB_LOAD_OK, DB_CORRUPT, + DB_NONCRITICAL_ERROR, DB_TOO_NEW, DB_LOAD_FAIL, DB_NEED_REWRITE @@ -35,21 +34,10 @@ private: CWalletDB(const CWalletDB&); void operator=(const CWalletDB&); public: - bool ReadName(const std::string& strAddress, std::string& strName) - { - strName = ""; - return Read(std::make_pair(std::string("name"), strAddress), strName); - } - bool WriteName(const std::string& strAddress, const std::string& strName); bool EraseName(const std::string& strAddress); - bool ReadTx(uint256 hash, CWalletTx& wtx) - { - return Read(std::make_pair(std::string("tx"), hash), wtx); - } - bool WriteTx(uint256 hash, const CWalletTx& wtx) { nWalletDBUpdated++; @@ -62,27 +50,21 @@ public: return Erase(std::make_pair(std::string("tx"), hash)); } - bool ReadKey(const CPubKey& vchPubKey, CPrivKey& vchPrivKey) - { - vchPrivKey.clear(); - return Read(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey); - } - bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false); + return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); } bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret, bool fEraseUnencryptedKey = true) { nWalletDBUpdated++; - if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false)) + if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) return false; if (fEraseUnencryptedKey) { - Erase(std::make_pair(std::string("key"), vchPubKey.Raw())); - Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw())); + Erase(std::make_pair(std::string("key"), vchPubKey)); + Erase(std::make_pair(std::string("wkey"), vchPubKey)); } return true; } @@ -93,13 +75,6 @@ public: return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); } - // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013 - bool ReadCScript(const uint160 &hash, CScript& redeemScript) - { - redeemScript.clear(); - return Read(std::make_pair(std::string("cscript"), hash), redeemScript); - } - bool WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdated++; @@ -117,16 +92,16 @@ public: return Read(std::string("bestblock"), locator); } - bool ReadDefaultKey(std::vector& vchPubKey) + bool WriteOrderPosNext(int64 nOrderPosNext) { - vchPubKey.clear(); - return Read(std::string("defaultkey"), vchPubKey); + nWalletDBUpdated++; + return Write(std::string("orderposnext"), nOrderPosNext); } bool WriteDefaultKey(const CPubKey& vchPubKey) { nWalletDBUpdated++; - return Write(std::string("defaultkey"), vchPubKey.Raw()); + return Write(std::string("defaultkey"), vchPubKey); } bool ReadPool(int64 nPool, CKeyPool& keypool) @@ -172,11 +147,17 @@ public: bool ReadAccount(const std::string& strAccount, CAccount& account); bool WriteAccount(const std::string& strAccount, const CAccount& account); +private: + bool WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry& acentry); +public: bool WriteAccountingEntry(const CAccountingEntry& acentry); int64 GetAccountCreditDebit(const std::string& strAccount); void ListAccountCreditDebit(const std::string& strAccount, std::list& acentries); - int LoadWallet(CWallet* pwallet); + DBErrors ReorderTransactions(CWallet*); + DBErrors LoadWallet(CWallet* pwallet); + static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys); + static bool Recover(CDBEnv& dbenv, std::string filename); }; #endif // BITCOIN_WALLETDB_H