diff options
Diffstat (limited to 'src')
76 files changed, 2864 insertions, 1258 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a49ad5871..3016be47b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,16 +1,35 @@ -include Makefile.include +AM_CPPFLAGS = $(INCLUDES) +AM_LDFLAGS = $(PTHREAD_CFLAGS) -AM_CPPFLAGS += -I$(builddir) + +if EMBEDDED_LEVELDB +LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include +LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv +LIBLEVELDB += $(builddir)/leveldb/libleveldb.a +LIBMEMENV += $(builddir)/leveldb/libmemenv.a + +# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race +$(LIBLEVELDB): $(LIBMEMENV) + +$(LIBLEVELDB) $(LIBMEMENV): + @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ + CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ + OPT="$(CXXFLAGS) $(CPPFLAGS)" +endif + +BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) noinst_LIBRARIES = \ libbitcoin_server.a \ libbitcoin_common.a \ libbitcoin_cli.a if ENABLE_WALLET +BITCOIN_INCLUDES += $(BDB_CPPFLAGS) noinst_LIBRARIES += libbitcoin_wallet.a endif bin_PROGRAMS = +TESTS = if BUILD_BITCOIND bin_PROGRAMS += bitcoind @@ -20,8 +39,6 @@ if BUILD_BITCOIN_CLI bin_PROGRAMS += bitcoin-cli endif -SUBDIRS = . $(BUILD_QT) $(BUILD_TEST) -DIST_SUBDIRS = . qt test .PHONY: FORCE # bitcoin core # BITCOIN_CORE_H = \ @@ -82,11 +99,12 @@ JSON_H = \ json/json_spirit_writer_template.h obj/build.h: FORCE - @$(MKDIR_P) $(abs_top_builddir)/src/obj + @$(MKDIR_P) $(builddir)/obj @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \ $(abs_top_srcdir) -version.o: obj/build.h +libbitcoin_common_a-version.$(OBJEXT): obj/build.h +libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_server_a_SOURCES = \ addrman.cpp \ alert.cpp \ @@ -111,6 +129,7 @@ libbitcoin_server_a_SOURCES = \ $(JSON_H) \ $(BITCOIN_CORE_H) +libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ db.cpp \ crypter.cpp \ @@ -120,6 +139,7 @@ libbitcoin_wallet_a_SOURCES = \ walletdb.cpp \ $(BITCOIN_CORE_H) +libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_common_a_SOURCES = \ base58.cpp \ allocators.cpp \ @@ -145,7 +165,7 @@ libbitcoin_cli_a_SOURCES = \ rpcclient.cpp \ $(BITCOIN_CORE_H) -nodist_libbitcoin_common_a_SOURCES = $(top_srcdir)/src/obj/build.h +nodist_libbitcoin_common_a_SOURCES = $(srcdir)/obj/build.h # # bitcoind binary # @@ -165,8 +185,8 @@ if TARGET_WINDOWS bitcoind_SOURCES += bitcoind-res.rc endif -AM_CPPFLAGS += $(BDB_CPPFLAGS) bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) +bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) # bitcoin-cli binary # bitcoin_cli_LDADD = \ @@ -174,30 +194,49 @@ bitcoin_cli_LDADD = \ libbitcoin_common.a \ $(BOOST_LIBS) bitcoin_cli_SOURCES = bitcoin-cli.cpp +bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES) # if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif -# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race -leveldb/libleveldb.a: leveldb/libmemenv.a - -leveldb/%.a: - @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ - CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(CXXFLAGS) $(CPPFLAGS)" - -qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_cli_a_SOURCES) - @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" - @cd $(top_srcdir); XGETTEXT=$(XGETTEXT) share/qt/extract_strings_qt.py - CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno DISTCLEANFILES = obj/build.h -EXTRA_DIST = leveldb Makefile.include +EXTRA_DIST = leveldb clean-local: -$(MAKE) -C leveldb clean rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno + +.rc.o: + @test -f $(WINDRES) + $(AM_V_GEN) $(WINDRES) -i $< -o $@ + +.mm.o: + $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $< + +%.pb.cc %.pb.h: %.proto + @test -f $(PROTOC) + $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<) + +LIBBITCOIN_SERVER=libbitcoin_server.a +LIBBITCOIN_WALLET=libbitcoin_wallet.a +LIBBITCOIN_COMMON=libbitcoin_common.a +LIBBITCOIN_CLI=libbitcoin_cli.a +LIBBITCOINQT=qt/libbitcoinqt.a + +if ENABLE_TESTS +include Makefile.test.include +endif + +if ENABLE_QT +include Makefile.qt.include +endif + +if ENABLE_QT_TESTS +include Makefile.qttest.include +endif diff --git a/src/Makefile.include b/src/Makefile.include deleted file mode 100644 index 2fc6cd777..000000000 --- a/src/Makefile.include +++ /dev/null @@ -1,79 +0,0 @@ -if EMBEDDED_LEVELDB -LEVELDB_CPPFLAGS += -I$(top_srcdir)/src/leveldb/include -LEVELDB_CPPFLAGS += -I$(top_srcdir)/src/leveldb/helpers/memenv -LIBLEVELDB += $(top_builddir)/src/leveldb/libleveldb.a -LIBMEMENV += $(top_builddir)/src/leveldb/libmemenv.a -endif - -AM_CPPFLAGS = $(INCLUDES) \ - -I$(top_builddir)/src/obj \ - $(BDB_CPPFLAGS) \ - $(BOOST_CPPFLAGS) $(BOOST_INCLUDES) -AM_CPPFLAGS += $(LEVELDB_CPPFLAGS) -AM_LDFLAGS = $(PTHREAD_CFLAGS) - -LIBBITCOIN_SERVER=$(top_builddir)/src/libbitcoin_server.a -LIBBITCOIN_WALLET=$(top_builddir)/src/libbitcoin_wallet.a -LIBBITCOIN_COMMON=$(top_builddir)/src/libbitcoin_common.a -LIBBITCOIN_CLI=$(top_builddir)/src/libbitcoin_cli.a -LIBBITCOINQT=$(top_builddir)/src/qt/libbitcoinqt.a - -$(LIBBITCOIN): - $(MAKE) -C $(top_builddir)/src $(@F) - -if EMBEDDED_LEVELDB -$(LIBLEVELDB) $(LIBMEMENV): - $(MAKE) -C $(top_builddir)/src leveldb/$(@F) -endif - -$(LIBBITCOINQT): - $(MAKE) -C $(top_builddir)/src/qt $(@F) - -.mm.o: - $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $< - -.rc.o: - @test -f $(WINDRES) && $(WINDRES) -i $< -o $@ || \ - echo error: could not build $@ - -ui_%.h: %.ui - @test -d $(abs_builddir)/$(@D) || $(MKDIR_P) $(abs_builddir)/$(@D) - @test -f $(UIC) && QT_SELECT=$(QT_SELECT) $(UIC) -o $(abs_builddir)/$@ $(abs_srcdir)/$< || echo error: could not build $(abs_builddir)/$@ - $(SED) -e '/^\*\*.*Created:/d' $(abs_builddir)/$@ > $(abs_builddir)/[email protected] && mv $(abs_builddir)/$@{.n,} - $(SED) -e '/^\*\*.*by:/d' $(abs_builddir)/$@ > $(abs_builddir)/[email protected] && mv $(abs_builddir)/$@{.n,} - -%.moc: %.cpp - QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) -o $@ $< - $(SED) -e '/^\*\*.*Created:/d' $@ > [email protected] && mv $@{.n,} - $(SED) -e '/^\*\*.*by:/d' $@ > [email protected] && mv $@{.n,} - -moc_%.cpp: %.h - QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) -o $@ $< - $(SED) -e '/^\*\*.*Created:/d' $@ > [email protected] && mv $@{.n,} - $(SED) -e '/^\*\*.*by:/d' $@ > [email protected] && mv $@{.n,} - -%.qm: %.ts - @test -d $(abs_builddir)/$(@D) || $(MKDIR_P) $(abs_builddir)/$(@D) - @test -f $(LRELEASE) && QT_SELECT=$(QT_SELECT) $(LRELEASE) $(abs_srcdir)/$< -qm $(abs_builddir)/$@ || \ - echo error: could not build $(abs_builddir)/$@ - -%.pb.cc %.pb.h: %.proto - test -f $(PROTOC) && $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<) || \ - echo error: could not build $@ - -%.json.h: %.json - @$(MKDIR_P) $(@D) - @echo "namespace json_tests{" > $@ - @echo "static unsigned const char $(*F)[] = {" >> $@ - @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ - @echo "};};" >> $@ - @echo "Generated $@" - -%.raw.h: %.raw - @$(MKDIR_P) $(@D) - @echo "namespace alert_tests{" > $@ - @echo "static unsigned const char $(*F)[] = {" >> $@ - @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ - @echo "};};" >> $@ - @echo "Generated $@" diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include new file mode 100644 index 000000000..72c748625 --- /dev/null +++ b/src/Makefile.qt.include @@ -0,0 +1,412 @@ +bin_PROGRAMS += qt/bitcoin-qt +noinst_LIBRARIES += qt/libbitcoinqt.a + +# bitcoin qt core # +QT_TS = \ + qt/locale/bitcoin_ach.ts \ + qt/locale/bitcoin_af_ZA.ts \ + qt/locale/bitcoin_ar.ts \ + qt/locale/bitcoin_be_BY.ts \ + qt/locale/bitcoin_bg.ts \ + qt/locale/bitcoin_bs.ts \ + qt/locale/bitcoin_ca_ES.ts \ + qt/locale/bitcoin_ca.ts \ + qt/locale/[email protected] \ + qt/locale/bitcoin_cmn.ts \ + qt/locale/bitcoin_cs.ts \ + qt/locale/bitcoin_cy.ts \ + qt/locale/bitcoin_da.ts \ + qt/locale/bitcoin_de.ts \ + qt/locale/bitcoin_el_GR.ts \ + qt/locale/bitcoin_en.ts \ + qt/locale/bitcoin_eo.ts \ + qt/locale/bitcoin_es_CL.ts \ + qt/locale/bitcoin_es_DO.ts \ + qt/locale/bitcoin_es_MX.ts \ + qt/locale/bitcoin_es.ts \ + qt/locale/bitcoin_es_UY.ts \ + qt/locale/bitcoin_et.ts \ + qt/locale/bitcoin_eu_ES.ts \ + qt/locale/bitcoin_fa_IR.ts \ + qt/locale/bitcoin_fa.ts \ + qt/locale/bitcoin_fi.ts \ + qt/locale/bitcoin_fr_CA.ts \ + qt/locale/bitcoin_fr.ts \ + qt/locale/bitcoin_gl.ts \ + qt/locale/bitcoin_gu_IN.ts \ + qt/locale/bitcoin_he.ts \ + qt/locale/bitcoin_hi_IN.ts \ + qt/locale/bitcoin_hr.ts \ + qt/locale/bitcoin_hu.ts \ + qt/locale/bitcoin_id_ID.ts \ + qt/locale/bitcoin_it.ts \ + qt/locale/bitcoin_ja.ts \ + qt/locale/bitcoin_ka.ts \ + qt/locale/bitcoin_kk_KZ.ts \ + qt/locale/bitcoin_ko_KR.ts \ + qt/locale/bitcoin_ky.ts \ + qt/locale/bitcoin_la.ts \ + qt/locale/bitcoin_lt.ts \ + qt/locale/bitcoin_lv_LV.ts \ + qt/locale/bitcoin_mn.ts \ + qt/locale/bitcoin_ms_MY.ts \ + qt/locale/bitcoin_nb.ts \ + qt/locale/bitcoin_nl.ts \ + qt/locale/bitcoin_pam.ts \ + qt/locale/bitcoin_pl.ts \ + qt/locale/bitcoin_pt_BR.ts \ + qt/locale/bitcoin_pt_PT.ts \ + qt/locale/bitcoin_ro_RO.ts \ + qt/locale/bitcoin_ru.ts \ + qt/locale/bitcoin_sah.ts \ + qt/locale/bitcoin_sk.ts \ + qt/locale/bitcoin_sl_SI.ts \ + qt/locale/bitcoin_sq.ts \ + qt/locale/bitcoin_sr.ts \ + qt/locale/bitcoin_sv.ts \ + qt/locale/bitcoin_th_TH.ts \ + qt/locale/bitcoin_tr.ts \ + qt/locale/bitcoin_uk.ts \ + qt/locale/bitcoin_ur_PK.ts \ + qt/locale/[email protected] \ + qt/locale/bitcoin_vi.ts \ + qt/locale/bitcoin_vi_VN.ts \ + qt/locale/bitcoin_zh_CN.ts \ + qt/locale/bitcoin_zh_HK.ts \ + qt/locale/bitcoin_zh_TW.ts + +QT_FORMS_UI = \ + qt/forms/aboutdialog.ui \ + qt/forms/addressbookpage.ui \ + qt/forms/askpassphrasedialog.ui \ + qt/forms/coincontroldialog.ui \ + qt/forms/editaddressdialog.ui \ + qt/forms/helpmessagedialog.ui \ + qt/forms/intro.ui \ + qt/forms/openuridialog.ui \ + qt/forms/optionsdialog.ui \ + qt/forms/overviewpage.ui \ + qt/forms/receivecoinsdialog.ui \ + qt/forms/receiverequestdialog.ui \ + qt/forms/rpcconsole.ui \ + qt/forms/sendcoinsdialog.ui \ + qt/forms/sendcoinsentry.ui \ + qt/forms/signverifymessagedialog.ui \ + qt/forms/transactiondescdialog.ui + +QT_MOC_CPP = \ + qt/moc_addressbookpage.cpp \ + qt/moc_addresstablemodel.cpp \ + qt/moc_askpassphrasedialog.cpp \ + qt/moc_bitcoinaddressvalidator.cpp \ + qt/moc_bitcoinamountfield.cpp \ + qt/moc_bitcoingui.cpp \ + qt/moc_bitcoinunits.cpp \ + qt/moc_clientmodel.cpp \ + qt/moc_coincontroldialog.cpp \ + qt/moc_coincontroltreewidget.cpp \ + qt/moc_csvmodelwriter.cpp \ + qt/moc_editaddressdialog.cpp \ + qt/moc_guiutil.cpp \ + qt/moc_intro.cpp \ + qt/moc_macdockiconhandler.cpp \ + qt/moc_macnotificationhandler.cpp \ + qt/moc_monitoreddatamapper.cpp \ + qt/moc_notificator.cpp \ + qt/moc_openuridialog.cpp \ + qt/moc_optionsdialog.cpp \ + qt/moc_optionsmodel.cpp \ + qt/moc_overviewpage.cpp \ + qt/moc_peertablemodel.cpp \ + qt/moc_paymentserver.cpp \ + qt/moc_qvalidatedlineedit.cpp \ + qt/moc_qvaluecombobox.cpp \ + qt/moc_receivecoinsdialog.cpp \ + qt/moc_receiverequestdialog.cpp \ + qt/moc_recentrequeststablemodel.cpp \ + qt/moc_rpcconsole.cpp \ + qt/moc_sendcoinsdialog.cpp \ + qt/moc_sendcoinsentry.cpp \ + qt/moc_signverifymessagedialog.cpp \ + qt/moc_splashscreen.cpp \ + qt/moc_trafficgraphwidget.cpp \ + qt/moc_transactiondesc.cpp \ + qt/moc_transactiondescdialog.cpp \ + qt/moc_transactionfilterproxy.cpp \ + qt/moc_transactiontablemodel.cpp \ + qt/moc_transactionview.cpp \ + qt/moc_utilitydialog.cpp \ + qt/moc_walletframe.cpp \ + qt/moc_walletmodel.cpp \ + qt/moc_walletview.cpp + +BITCOIN_MM = \ + qt/macdockiconhandler.mm \ + qt/macnotificationhandler.mm + +QT_MOC = \ + qt/bitcoin.moc \ + qt/intro.moc \ + qt/overviewpage.moc \ + qt/rpcconsole.moc + +QT_QRC_CPP = qt/qrc_bitcoin.cpp +QT_QRC = qt/bitcoin.qrc +QT_QRC_LOCALE_CPP = qt/qrc_bitcoin_locale.cpp +QT_QRC_LOCALE = qt/bitcoin_locale.qrc + +PROTOBUF_CC = qt/paymentrequest.pb.cc +PROTOBUF_H = qt/paymentrequest.pb.h +PROTOBUF_PROTO = qt/paymentrequest.proto + +BITCOIN_QT_H = \ + qt/addressbookpage.h \ + qt/addresstablemodel.h \ + qt/askpassphrasedialog.h \ + qt/bitcoinaddressvalidator.h \ + qt/bitcoinamountfield.h \ + qt/bitcoingui.h \ + qt/bitcoinunits.h \ + qt/clientmodel.h \ + qt/coincontroldialog.h \ + qt/coincontroltreewidget.h \ + qt/csvmodelwriter.h \ + qt/editaddressdialog.h \ + qt/guiconstants.h \ + qt/guiutil.h \ + qt/intro.h \ + qt/macdockiconhandler.h \ + qt/macnotificationhandler.h \ + qt/monitoreddatamapper.h \ + qt/notificator.h \ + qt/openuridialog.h \ + qt/optionsdialog.h \ + qt/optionsmodel.h \ + qt/overviewpage.h \ + qt/paymentrequestplus.h \ + qt/paymentserver.h \ + qt/peertablemodel.h \ + qt/qvalidatedlineedit.h \ + qt/qvaluecombobox.h \ + qt/receivecoinsdialog.h \ + qt/receiverequestdialog.h \ + qt/recentrequeststablemodel.h \ + qt/rpcconsole.h \ + qt/sendcoinsdialog.h \ + qt/sendcoinsentry.h \ + qt/signverifymessagedialog.h \ + qt/splashscreen.h \ + qt/trafficgraphwidget.h \ + qt/transactiondesc.h \ + qt/transactiondescdialog.h \ + qt/transactionfilterproxy.h \ + qt/transactionrecord.h \ + qt/transactiontablemodel.h \ + qt/transactionview.h \ + qt/utilitydialog.h \ + qt/walletframe.h \ + qt/walletmodel.h \ + qt/walletmodeltransaction.h \ + qt/walletview.h \ + qt/winshutdownmonitor.h + +RES_ICONS = \ + qt/res/icons/add.png \ + qt/res/icons/address-book.png \ + qt/res/icons/bitcoin.ico \ + qt/res/icons/bitcoin.png \ + qt/res/icons/bitcoin_testnet.ico \ + qt/res/icons/bitcoin_testnet.png \ + qt/res/icons/clock1.png \ + qt/res/icons/clock2.png \ + qt/res/icons/clock3.png \ + qt/res/icons/clock4.png \ + qt/res/icons/clock5.png \ + qt/res/icons/configure.png \ + qt/res/icons/connect0_16.png \ + qt/res/icons/connect1_16.png \ + qt/res/icons/connect2_16.png \ + qt/res/icons/connect3_16.png \ + qt/res/icons/connect4_16.png \ + qt/res/icons/debugwindow.png \ + qt/res/icons/edit.png \ + qt/res/icons/editcopy.png \ + qt/res/icons/editpaste.png \ + qt/res/icons/export.png \ + qt/res/icons/filesave.png \ + qt/res/icons/history.png \ + qt/res/icons/key.png \ + qt/res/icons/lock_closed.png \ + qt/res/icons/lock_open.png \ + qt/res/icons/overview.png \ + qt/res/icons/qrcode.png \ + qt/res/icons/quit.png \ + qt/res/icons/receive.png \ + qt/res/icons/remove.png \ + qt/res/icons/send.png \ + qt/res/icons/synced.png \ + qt/res/icons/toolbar.png \ + qt/res/icons/toolbar_testnet.png \ + qt/res/icons/transaction0.png \ + qt/res/icons/transaction2.png \ + qt/res/icons/transaction_conflicted.png \ + qt/res/icons/tx_inout.png \ + qt/res/icons/tx_input.png \ + qt/res/icons/tx_output.png \ + qt/res/icons/tx_mined.png + +BITCOIN_QT_CPP = \ + qt/bitcoinaddressvalidator.cpp \ + qt/bitcoinamountfield.cpp \ + qt/bitcoingui.cpp \ + qt/bitcoinunits.cpp \ + qt/clientmodel.cpp \ + qt/csvmodelwriter.cpp \ + qt/guiutil.cpp \ + qt/intro.cpp \ + qt/monitoreddatamapper.cpp \ + qt/notificator.cpp \ + qt/optionsdialog.cpp \ + qt/optionsmodel.cpp \ + qt/peertablemodel.cpp \ + qt/qvalidatedlineedit.cpp \ + qt/qvaluecombobox.cpp \ + qt/rpcconsole.cpp \ + qt/splashscreen.cpp \ + qt/trafficgraphwidget.cpp \ + qt/utilitydialog.cpp \ + qt/winshutdownmonitor.cpp + +if ENABLE_WALLET +BITCOIN_QT_CPP += \ + qt/addressbookpage.cpp \ + qt/addresstablemodel.cpp \ + qt/askpassphrasedialog.cpp \ + qt/coincontroldialog.cpp \ + qt/coincontroltreewidget.cpp \ + qt/editaddressdialog.cpp \ + qt/openuridialog.cpp \ + qt/overviewpage.cpp \ + qt/paymentrequestplus.cpp \ + qt/paymentserver.cpp \ + qt/receivecoinsdialog.cpp \ + qt/receiverequestdialog.cpp \ + qt/recentrequeststablemodel.cpp \ + qt/sendcoinsdialog.cpp \ + qt/sendcoinsentry.cpp \ + qt/signverifymessagedialog.cpp \ + qt/transactiondesc.cpp \ + qt/transactiondescdialog.cpp \ + qt/transactionfilterproxy.cpp \ + qt/transactionrecord.cpp \ + qt/transactiontablemodel.cpp \ + qt/transactionview.cpp \ + qt/walletframe.cpp \ + qt/walletmodel.cpp \ + qt/walletmodeltransaction.cpp \ + qt/walletview.cpp +endif + +RES_IMAGES = \ + qt/res/images/about.png \ + qt/res/images/splash.png \ + qt/res/images/splash_testnet.png + +RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png) + +BITCOIN_RC = qt/res/bitcoin-qt-res.rc + +BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \ + -I$(builddir)/qt/forms + +qt_libbitcoinqt_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ + $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) + +qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \ + $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) + +nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \ + $(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP) + +# forms/foo.h -> forms/ui_foo.h +QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h)))) + +# Most files will depend on the forms and moc files as includes. Generate them +# before anything else. +$(QT_MOC): $(QT_FORMS_H) +$(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) : | $(QT_MOC) + +#Generating these with a half-written protobuf header leads to wacky results. +#This makes sure it's done. +$(QT_MOC): $(PROTOBUF_H) +$(QT_MOC_CPP): $(PROTOBUF_H) + +# bitcoin-qt binary # +qt_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ + $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) + +qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp +if TARGET_DARWIN + qt_bitcoin_qt_SOURCES += $(BITCOIN_MM) +endif +if TARGET_WINDOWS + qt_bitcoin_qt_SOURCES += $(BITCOIN_RC) +endif +qt_bitcoin_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER) +if ENABLE_WALLET +qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) +endif +qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ + $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) +qt_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS) + +#locale/foo.ts -> locale/foo.qm +QT_QM=$(QT_TS:.ts=.qm) + +.SECONDARY: $(QT_QM) + +qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_cli_a_SOURCES) + @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" + $(AM_V_GEN) cd $(top_srcdir); XGETTEXT=$(XGETTEXT) share/qt/extract_strings_qt.py + +translate: qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) + @test -n $(LUPDATE) || echo "lupdate is required for updating translations" + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts qt/locale/bitcoin_en.ts + +$(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) + @test -f $(RCC) + @test -f $(@D)/$(<F) || cp -f $< $(@D) + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale $(@D)/$(<F) | \ + $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ + +$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H) + @test -f $(RCC) + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin $< | \ + $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ + +CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno + +CLEANFILES += $(CLEAN_QT) + +bitcoin_qt_clean: FORCE + rm -f $(CLEAN_QT) $(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) qt/bitcoin-qt$(EXEEXT) $(LIBBITCOINQT) + +bitcoin_qt : qt/bitcoin-qt$(EXEEXT) + +ui_%.h: %.ui + @test -f $(UIC) + @$(MKDIR_P) $(@D) + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false) + +%.moc: %.cpp + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) $< | \ + $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ + +moc_%.cpp: %.h + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) $< | \ + $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ + +%.qm: %.ts + @test -f $(LRELEASE) + @$(MKDIR_P) $(@D) + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@ diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include new file mode 100644 index 000000000..e0b49d024 --- /dev/null +++ b/src/Makefile.qttest.include @@ -0,0 +1,48 @@ +bin_PROGRAMS += qt/test/test_bitcoin-qt +TESTS += qt/test/test_bitcoin-qt + +TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp + +if ENABLE_WALLET +TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp +endif + +TEST_QT_H = \ + qt/test/uritests.h \ + qt/test/paymentrequestdata.h \ + qt/test/paymentservertests.h + +qt_test_test_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ + $(QT_INCLUDES) $(QT_TEST_INCLUDES) + +qt_test_test_bitcoin_qt_SOURCES = \ + qt/test/test_main.cpp \ + qt/test/uritests.cpp \ + $(TEST_QT_H) +if ENABLE_WALLET +qt_test_test_bitcoin_qt_SOURCES += \ + qt/test/paymentservertests.cpp +endif + +nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) + +qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) +if ENABLE_WALLET +qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) +endif +qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \ + $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ + $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) +qt_test_test_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS) + +CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno + +CLEANFILES += $(CLEAN_BITCOIN_QT_TEST) + +test_bitcoin_qt : qt/test/test_bitcoin-qt$(EXEEXT) + +test_bitcoin_qt_check : qt/test/test_bitcoin-qt$(EXEEXT) FORCE + $(MAKE) check-TESTS TESTS=$^ + +test_bitcoin_qt_clean: FORCE + rm -f $(CLEAN_BITCOIN_QT_TEST) $(qt_test_test_bitcoin_qt_OBJECTS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include new file mode 100644 index 000000000..988830260 --- /dev/null +++ b/src/Makefile.test.include @@ -0,0 +1,101 @@ +TESTS += test/test_bitcoin +bin_PROGRAMS += test/test_bitcoin +TEST_SRCDIR = test +TEST_BINARY=test/test_bitcoin$(EXEEXT) + +JSON_TEST_FILES = \ + test/data/script_valid.json \ + test/data/base58_keys_valid.json \ + test/data/sig_canonical.json \ + test/data/sig_noncanonical.json \ + test/data/base58_encode_decode.json \ + test/data/base58_keys_invalid.json \ + test/data/script_invalid.json \ + test/data/tx_invalid.json \ + test/data/tx_valid.json \ + test/data/sighash.json + +RAW_TEST_FILES = test/data/alertTests.raw + +GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) + +BITCOIN_TESTS =\ + test/bignum.h \ + test/alert_tests.cpp \ + test/allocator_tests.cpp \ + test/base32_tests.cpp \ + test/base58_tests.cpp \ + test/base64_tests.cpp \ + test/bloom_tests.cpp \ + test/canonical_tests.cpp \ + test/checkblock_tests.cpp \ + test/Checkpoints_tests.cpp \ + test/compress_tests.cpp \ + test/DoS_tests.cpp \ + test/getarg_tests.cpp \ + test/key_tests.cpp \ + test/main_tests.cpp \ + test/miner_tests.cpp \ + test/mruset_tests.cpp \ + test/multisig_tests.cpp \ + test/netbase_tests.cpp \ + test/pmt_tests.cpp \ + test/rpc_tests.cpp \ + test/script_P2SH_tests.cpp \ + test/script_tests.cpp \ + test/serialize_tests.cpp \ + test/sigopcount_tests.cpp \ + test/test_bitcoin.cpp \ + test/transaction_tests.cpp \ + test/uint256_tests.cpp \ + test/util_tests.cpp \ + test/scriptnum_tests.cpp \ + test/sighash_tests.cpp + +if ENABLE_WALLET +BITCOIN_TESTS += \ + test/accounting_tests.cpp \ + test/wallet_tests.cpp \ + test/rpc_wallet_tests.cpp +endif + +test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) +test_test_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) +test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ + $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) +if ENABLE_WALLET +test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) +endif +test_test_bitcoin_LDADD += $(BDB_LIBS) + +nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) + +$(BITCOIN_TESTS): $(GENERATED_TEST_FILES) + +CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) + +CLEANFILES += $(CLEAN_BITCOIN_TEST) + +bitcoin_test: $(TEST_BINARY) + +bitcoin_test_check: $(TEST_BINARY) FORCE + $(MAKE) check-TESTS TESTS=$^ + +bitcoin_test_clean : FORCE + rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) + +%.json.h: %.json + @$(MKDIR_P) $(@D) + @echo "namespace json_tests{" > $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ + @echo "};};" >> $@ + @echo "Generated $@" + +%.raw.h: %.raw + @$(MKDIR_P) $(@D) + @echo "namespace alert_tests{" > $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ + @echo "};};" >> $@ + @echo "Generated $@" diff --git a/src/alert.cpp b/src/alert.cpp index 99164d63e..638f0d7a1 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -5,6 +5,7 @@ #include "alert.h" +#include "chainparams.h" #include "key.h" #include "net.h" #include "ui_interface.h" diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index ce9e7a402..29efdfa82 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -33,7 +33,7 @@ static bool AppInitRPC(int argc, char* argv[]) fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } - // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) + // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) if (!SelectParamsFromCommandLine()) { fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n"); return false; diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 9b535c2e6..704332c39 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -77,7 +77,7 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } - // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) + // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) if (!SelectParamsFromCommandLine()) { fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n"); return false; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f5cf846a0..3f4d7f706 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -6,8 +6,6 @@ #include "chainparams.h" #include "assert.h" -#include "core.h" -#include "protocol.h" #include "util.h" #include <boost/assign/list_of.hpp> @@ -100,6 +98,7 @@ unsigned int pnSeed[] = class CMainParams : public CChainParams { public: CMainParams() { + networkID = CChainParams::MAIN; // 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 // a large 4-byte int at any alignment. @@ -112,6 +111,10 @@ public: nRPCPort = 8332; bnProofOfWorkLimit = ~uint256(0) >> 32; nSubsidyHalvingInterval = 210000; + nEnforceBlockUpgradeMajority = 750; + nRejectBlockOutdatedMajority = 950; + nToCheckBlockUpgradeMajority = 1000; + nMinerThreads = 0; // Build the genesis block. Note that the output of the genesis coinbase cannot // be spent as it did not originally exist in the database. @@ -167,27 +170,25 @@ public: addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; vFixedSeeds.push_back(addr); } - } - - virtual const CBlock& GenesisBlock() const { return genesis; } - virtual Network NetworkID() const { return CChainParams::MAIN; } - virtual const vector<CAddress>& FixedSeeds() const { - return vFixedSeeds; + fRequireRPCPassword = true; + fMiningRequiresPeers = true; + fDefaultCheckMemPool = false; + fAllowMinDifficultyBlocks = false; + fRequireStandard = true; + fRPCisTestNet = false; + fMineBlocksOnDemand = false; } -protected: - CBlock genesis; - vector<CAddress> vFixedSeeds; }; static CMainParams mainParams; - // // Testnet (v3) // class CTestNetParams : public CMainParams { public: CTestNetParams() { + networkID = CChainParams::TESTNET; // 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 // a large 4-byte int at any alignment. @@ -198,6 +199,9 @@ public: vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); nDefaultPort = 18333; nRPCPort = 18332; + nEnforceBlockUpgradeMajority = 51; + nRejectBlockOutdatedMajority = 75; + nToCheckBlockUpgradeMajority = 100; strDataDir = "testnet3"; // Modify the testnet genesis block so the timestamp is valid for a later start. @@ -216,23 +220,34 @@ public: base58Prefixes[SECRET_KEY] = list_of(239); base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x35)(0x87)(0xCF); base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x35)(0x83)(0x94); + + fRequireRPCPassword = true; + fMiningRequiresPeers = true; + fDefaultCheckMemPool = false; + fAllowMinDifficultyBlocks = true; + fRequireStandard = false; + fRPCisTestNet = true; + fMineBlocksOnDemand = false; } - virtual Network NetworkID() const { return CChainParams::TESTNET; } }; static CTestNetParams testNetParams; - // // Regression test // class CRegTestParams : public CTestNetParams { public: CRegTestParams() { + networkID = CChainParams::REGTEST; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; nSubsidyHalvingInterval = 150; + nEnforceBlockUpgradeMajority = 750; + nRejectBlockOutdatedMajority = 950; + nToCheckBlockUpgradeMajority = 1000; + nMinerThreads = 1; bnProofOfWorkLimit = ~uint256(0) >> 1; genesis.nTime = 1296688602; genesis.nBits = 0x207fffff; @@ -243,10 +258,15 @@ public: assert(hashGenesisBlock == uint256("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); vSeeds.clear(); // Regtest mode doesn't have any DNS seeds. - } - virtual bool RequireRPCPassword() const { return false; } - virtual Network NetworkID() const { return CChainParams::REGTEST; } + fRequireRPCPassword = false; + fMiningRequiresPeers = false; + fDefaultCheckMemPool = true; + fAllowMinDifficultyBlocks = true; + fRequireStandard = false; + fRPCisTestNet = true; + fMineBlocksOnDemand = true; + } }; static CRegTestParams regTestParams; diff --git a/src/chainparams.h b/src/chainparams.h index 5600b904c..8370cc569 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -6,18 +6,16 @@ #ifndef BITCOIN_CHAIN_PARAMS_H #define BITCOIN_CHAIN_PARAMS_H +#include "core.h" +#include "protocol.h" #include "uint256.h" #include <vector> using namespace std; -#define MESSAGE_START_SIZE 4 typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; -class CAddress; -class CBlock; - struct CDNSSeedData { string name, host; CDNSSeedData(const string &strName, const string &strHost) : name(strName), host(strHost) {} @@ -57,13 +55,33 @@ public: int GetDefaultPort() const { return nDefaultPort; } const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } - virtual const CBlock& GenesisBlock() const = 0; - virtual bool RequireRPCPassword() const { return true; } + /* Used to check majorities for block version upgrade */ + int EnforceBlockUpgradeMajority() const { return nEnforceBlockUpgradeMajority; } + int RejectBlockOutdatedMajority() const { return nRejectBlockOutdatedMajority; } + int ToCheckBlockUpgradeMajority() const { return nToCheckBlockUpgradeMajority; } + + /* Used if GenerateBitcoins is called with a negative number of threads */ + int DefaultMinerThreads() const { return nMinerThreads; } + const CBlock& GenesisBlock() const { return genesis; } + bool RequireRPCPassword() const { return fRequireRPCPassword; } + /* Make miner wait to have peers to avoid wasting work */ + bool MiningRequiresPeers() const { return fMiningRequiresPeers; } + /* Default value for -checkmempool argument */ + bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; } + /* Allow mining of a min-difficulty block */ + bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; } + /* Make standard checks */ + bool RequireStandard() const { return fRequireStandard; } + /* Make standard checks */ + bool RPCisTestNet() const { return fRPCisTestNet; } const string& DataDir() const { return strDataDir; } - virtual Network NetworkID() const = 0; + /* Make miner stop after a block is found. In RPC, don't return + * until nGenProcLimit blocks are generated */ + bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } + Network NetworkID() const { return networkID; } const vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; } - const std::vector<unsigned char> &Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } - virtual const vector<CAddress>& FixedSeeds() const = 0; + const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } + const vector<CAddress>& FixedSeeds() const { return vFixedSeeds; } int RPCPort() const { return nRPCPort; } protected: CChainParams() {} @@ -76,9 +94,23 @@ protected: int nRPCPort; uint256 bnProofOfWorkLimit; int nSubsidyHalvingInterval; + int nEnforceBlockUpgradeMajority; + int nRejectBlockOutdatedMajority; + int nToCheckBlockUpgradeMajority; string strDataDir; + int nMinerThreads; vector<CDNSSeedData> vSeeds; std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; + Network networkID; + CBlock genesis; + vector<CAddress> vFixedSeeds; + bool fRequireRPCPassword; + bool fMiningRequiresPeers; + bool fDefaultCheckMemPool; + bool fAllowMinDifficultyBlocks; + bool fRequireStandard; + bool fRPCisTestNet; + bool fMineBlocksOnDemand; }; /** @@ -96,13 +128,4 @@ void SelectParams(CChainParams::Network network); */ bool SelectParamsFromCommandLine(); -inline bool TestNet() { - // Note: it's deliberate that this returns "false" for regression test mode. - return Params().NetworkID() == CChainParams::TESTNET; -} - -inline bool RegTest() { - return Params().NetworkID() == CChainParams::REGTEST; -} - #endif diff --git a/src/core.cpp b/src/core.cpp index aadcb44b9..6039986e6 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -72,6 +72,25 @@ void CTxOut::print() const LogPrintf("%s\n", ToString()); } +CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize) +{ + if (nSize > 0) + nSatoshisPerK = nFeePaid*1000/nSize; + else + nSatoshisPerK = 0; +} + +int64_t CFeeRate::GetFee(size_t nSize) +{ + return nSatoshisPerK*nSize / 1000; +} + +std::string CFeeRate::ToString() const +{ + std::string result = FormatMoney(nSatoshisPerK) + " BTC/kB"; + return result; +} + uint256 CTransaction::GetHash() const { return SerializeHash(*this); diff --git a/src/core.h b/src/core.h index ba7f69111..0e5912934 100644 --- a/src/core.h +++ b/src/core.h @@ -112,6 +112,31 @@ public: +/** Type-safe wrapper class to for fee rates + * (how much to pay based on transaction size) + */ +class CFeeRate +{ +private: + int64_t nSatoshisPerK; // unit is satoshis-per-1,000-bytes +public: + CFeeRate() : nSatoshisPerK(0) { } + explicit CFeeRate(int64_t _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } + CFeeRate(int64_t nFeePaid, size_t nSize); + CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } + + int64_t GetFee(size_t size); // unit returned is satoshis + int64_t GetFeePerK() { return GetFee(1000); } // satoshis-per-1000-bytes + + friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; } + friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; } + friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; } + + std::string ToString() const; + + IMPLEMENT_SERIALIZE( READWRITE(nSatoshisPerK); ) +}; + /** An output of a transaction. It contains the public key that the next input * must be able to sign with to claim it. @@ -148,17 +173,18 @@ public: uint256 GetHash() const; - bool IsDust(int64_t nMinRelayTxFee) const + bool IsDust(CFeeRate minRelayTxFee) const { - // "Dust" is defined in terms of CTransaction::nMinRelayTxFee, + // "Dust" is defined in terms of CTransaction::minRelayTxFee, // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees // to spend something, then we consider it dust. // A typical txout is 34 bytes big, and will - // need a CTxIn of at least 148 bytes to spend, + // need a CTxIn of at least 148 bytes to spend: // so dust is a txout less than 546 satoshis - // with default nMinRelayTxFee. - return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < nMinRelayTxFee); + // with default minRelayTxFee. + size_t nSize = GetSerializeSize(SER_DISK,0)+148u; + return (nValue < 3*minRelayTxFee.GetFee(nSize)); } friend bool operator==(const CTxOut& a, const CTxOut& b) @@ -183,8 +209,8 @@ public: class CTransaction { public: - static int64_t nMinTxFee; - static int64_t nMinRelayTxFee; + static CFeeRate minTxFee; + static CFeeRate minRelayTxFee; static const int CURRENT_VERSION=1; int nVersion; std::vector<CTxIn> vin; diff --git a/src/init.cpp b/src/init.cpp index b66231ff2..1d86cf087 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -41,7 +41,6 @@ using namespace std; using namespace boost; #ifdef ENABLE_WALLET -std::string strWalletFile; CWallet* pwalletMain; #endif @@ -61,6 +60,7 @@ enum BindFlags { BF_REPORT_ERROR = (1U << 1) }; +static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; ////////////////////////////////////////////////////////////////////////////// // @@ -123,6 +123,14 @@ void Shutdown() #endif StopNode(); UnregisterNodeSignals(GetNodeSignals()); + + boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; + CAutoFile est_fileout = CAutoFile(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION); + if (est_fileout) + mempool.WriteFeeEstimates(est_fileout); + else + LogPrintf("failed to write fee estimates"); + { LOCK(cs_main); #ifdef ENABLE_WALLET @@ -207,6 +215,7 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += " -dbcache=<n> " + strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache) + "\n"; strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n"; strUsage += " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + " " + _("on startup") + "\n"; + strUsage += " -maxorphanblocks=<n> " + strprintf(_("Keep at most <n> unconnectable blocks in memory (default: %u)"), DEFAULT_MAX_ORPHAN_BLOCKS) + "\n"; strUsage += " -par=<n> " + strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS) + "\n"; strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n"; strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup") + "\n"; @@ -282,8 +291,8 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += " -limitfreerelay=<n> " + _("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)") + "\n"; strUsage += " -maxsigcachesize=<n> " + _("Limit size of signature cache to <n> entries (default: 50000)") + "\n"; } - strUsage += " -mintxfee=<amt> " + _("Fees smaller than this are considered zero fee (for transaction creation) (default:") + " " + FormatMoney(CTransaction::nMinTxFee) + ")" + "\n"; - strUsage += " -minrelaytxfee=<amt> " + _("Fees smaller than this are considered zero fee (for relaying) (default:") + " " + FormatMoney(CTransaction::nMinRelayTxFee) + ")" + "\n"; + strUsage += " -mintxfee=<amt> " + _("Fees smaller than this are considered zero fee (for transaction creation) (default:") + " " + FormatMoney(CTransaction::minTxFee.GetFeePerK()) + ")" + "\n"; + strUsage += " -minrelaytxfee=<amt> " + _("Fees smaller than this are considered zero fee (for relaying) (default:") + " " + FormatMoney(CTransaction::minRelayTxFee.GetFeePerK()) + ")" + "\n"; strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n"; if (GetBoolArg("-help-debug", false)) { @@ -535,7 +544,8 @@ bool AppInit2(boost::thread_group& threadGroup) InitWarning(_("Warning: Deprecated argument -debugnet ignored, use -debug=net")); fBenchmark = GetBoolArg("-benchmark", false); - mempool.setSanityCheck(GetBoolArg("-checkmempool", RegTest())); + // Checkmempool defaults to true in regtest mode + mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultCheckMemPool())); Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency @@ -578,7 +588,7 @@ bool AppInit2(boost::thread_group& threadGroup) { int64_t n = 0; if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) - CTransaction::nMinTxFee = n; + CTransaction::minTxFee = CFeeRate(n); else return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"])); } @@ -586,7 +596,7 @@ bool AppInit2(boost::thread_group& threadGroup) { int64_t n = 0; if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) - CTransaction::nMinRelayTxFee = n; + CTransaction::minRelayTxFee = CFeeRate(n); else return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"])); } @@ -594,14 +604,16 @@ bool AppInit2(boost::thread_group& threadGroup) #ifdef ENABLE_WALLET if (mapArgs.count("-paytxfee")) { - if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) + int64_t nFeePerK = 0; + if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"])); - if (nTransactionFee > nHighTransactionFeeWarning) + if (nFeePerK > nHighTransactionFeeWarning) InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + payTxFee = CFeeRate(nFeePerK, 1000); } bSpendZeroConfChange = GetArg("-spendzeroconfchange", true); - strWalletFile = GetArg("-wallet", "wallet.dat"); + std::string strWalletFile = GetArg("-wallet", "wallet.dat"); #endif // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Sanity check @@ -634,6 +646,7 @@ bool AppInit2(boost::thread_group& threadGroup) LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Using data directory %s\n", strDataDir); + LogPrintf("Using config file %s\n", GetConfigFile().string()); LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); std::ostringstream strErrors; @@ -753,12 +766,12 @@ bool AppInit2(boost::thread_group& threadGroup) } // see Step 2: parameter interactions for more information about these - fNoListen = !GetBoolArg("-listen", true); + fListen = GetBoolArg("-listen", true); fDiscover = GetBoolArg("-discover", true); fNameLookup = GetBoolArg("-dns", true); bool fBound = false; - if (!fNoListen) { + if (fListen) { if (mapArgs.count("-bind")) { BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) { CService addrBind; @@ -879,7 +892,7 @@ bool AppInit2(boost::thread_group& threadGroup) } uiInterface.InitMessage(_("Verifying blocks...")); - if (!VerifyDB(GetArg("-checklevel", 3), + if (!CVerifyDB().VerifyDB(GetArg("-checklevel", 3), GetArg("-checkblocks", 288))) { strLoadError = _("Corrupted block database detected"); break; @@ -951,6 +964,11 @@ bool AppInit2(boost::thread_group& threadGroup) return false; } + boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; + CAutoFile est_filein = CAutoFile(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION); + if (est_filein) + mempool.ReadFeeEstimates(est_filein); + // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET if (fDisableWallet) { diff --git a/src/init.h b/src/init.h index 2f5692305..4a967bea3 100644 --- a/src/init.h +++ b/src/init.h @@ -14,7 +14,6 @@ namespace boost { class thread_group; }; -extern std::string strWalletFile; extern CWallet* pwalletMain; void StartShutdown(); diff --git a/src/m4/bitcoin_qt.m4 b/src/m4/bitcoin_qt.m4 index e71ecd717..244b03a5c 100644 --- a/src/m4/bitcoin_qt.m4 +++ b/src/m4/bitcoin_qt.m4 @@ -100,7 +100,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt${bitcoin_qt_got_major_vers} lrelease${bitcoin_qt_got_major_vers} lrelease], $qt_bin_path) BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt${bitcoin_qt_got_major_vers} lupdate${bitcoin_qt_got_major_vers} lupdate],$qt_bin_path, yes) - MOC_DEFS='-DHAVE_CONFIG_H -I$(top_srcdir)/src' + MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)' case $host in *darwin*) BITCOIN_QT_CHECK([ diff --git a/src/main.cpp b/src/main.cpp index 18c00d90a..5d1ff94f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,7 +40,6 @@ CTxMemPool mempool; map<uint256, CBlockIndex*> mapBlockIndex; CChain chainActive; -CChain chainMostWork; int64_t nTimeBestReceived = 0; int nScriptCheckThreads = 0; bool fImporting = false; @@ -50,9 +49,9 @@ bool fTxIndex = false; unsigned int nCoinCacheSize = 5000; /** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ -int64_t CTransaction::nMinTxFee = 10000; // Override with -mintxfee +CFeeRate CTransaction::minTxFee = CFeeRate(10000); // Override with -mintxfee /** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ -int64_t CTransaction::nMinRelayTxFee = 1000; +CFeeRate CTransaction::minRelayTxFee = CFeeRate(1000); struct COrphanBlock { uint256 hashBlock; @@ -398,6 +397,12 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const { return Genesis(); } +CBlockIndex *CChain::FindFork(CBlockIndex *pindex) const { + while (pindex && !Contains(pindex)) + pindex = pindex->pprev; + return pindex; +} + CCoinsViewCache *pcoinsTip = NULL; CBlockTreeDB *pblocktree = NULL; @@ -543,7 +548,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) } if (whichType == TX_NULL_DATA) nDataOut++; - else if (txout.IsDust(CTransaction::nMinRelayTxFee)) { + else if (txout.IsDust(CTransaction::minRelayTxFee)) { reason = "dust"; return false; } @@ -783,10 +788,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode) { - // Base fee is either nMinTxFee or nMinRelayTxFee - int64_t nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee; + // Base fee is either minTxFee or minRelayTxFee + CFeeRate baseFeeRate = (mode == GMF_RELAY) ? tx.minRelayTxFee : tx.minTxFee; - int64_t nMinFee = (1 + (int64_t)nBytes / 1000) * nBaseFee; + int64_t nMinFee = baseFeeRate.GetFee(nBytes); if (fAllowFree) { @@ -800,16 +805,6 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, nMinFee = 0; } - // This code can be removed after enough miners have upgraded to version 0.9. - // Until then, be safe when sending and require a fee if any output - // is less than CENT: - if (nMinFee < nBaseFee && mode == GMF_SEND) - { - BOOST_FOREACH(const CTxOut& txout, tx.vout) - if (txout.nValue < CENT) - nMinFee = nBaseFee; - } - if (!MoneyRange(nMinFee)) nMinFee = MAX_MONEY; return nMinFee; @@ -833,7 +828,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; - if (Params().NetworkID() == CChainParams::MAIN && !IsStandardTx(tx, reason)) + if (Params().RequireStandard() && !IsStandardTx(tx, reason)) return state.DoS(0, error("AcceptToMemoryPool : nonstandard transaction: %s", reason), REJECT_NONSTANDARD, reason); @@ -861,6 +856,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CCoinsView dummy; CCoinsViewCache view(dummy); + int64_t nValueIn = 0; { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(*pcoinsTip, pool); @@ -889,19 +885,20 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Bring the best block into scope view.GetBestBlock(); + nValueIn = view.GetValueIn(tx); + // 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 (Params().NetworkID() == CChainParams::MAIN && !AreInputsStandard(tx, view)) + if (Params().RequireStandard() && !AreInputsStandard(tx, view)) return error("AcceptToMemoryPool: : 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_t nValueIn = view.GetValueIn(tx); int64_t nValueOut = tx.GetValueOut(); int64_t nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); @@ -916,10 +913,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); - // Continuously rate-limit free transactions + // Continuously rate-limit free (really, very-low-fee)transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < CTransaction::nMinRelayTxFee) + if (fLimitFree && nFees < CTransaction::minRelayTxFee.GetFee(nSize)) { static CCriticalSection csFreeLimiter; static double dFreeCount; @@ -940,10 +937,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa dFreeCount += nSize; } - if (fRejectInsaneFee && nFees > CTransaction::nMinRelayTxFee * 10000) + if (fRejectInsaneFee && nFees > CTransaction::minRelayTxFee.GetFee(nSize) * 10000) return error("AcceptToMemoryPool: : insane fees %s, %d > %d", hash.ToString(), - nFees, CTransaction::nMinRelayTxFee * 10000); + nFees, CTransaction::minRelayTxFee.GetFee(nSize) * 10000); // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. @@ -1160,7 +1157,7 @@ uint256 static GetOrphanRoot(const uint256& hash) // Remove a random orphan block (which does not have any dependent orphans). void static PruneOrphanBlocks() { - if (mapOrphanBlocksByPrev.size() <= MAX_ORPHAN_BLOCKS) + if (mapOrphanBlocksByPrev.size() <= (size_t)std::max((int64_t)0, GetArg("-maxorphanblocks", DEFAULT_MAX_ORPHAN_BLOCKS))) return; // Pick a random orphan block. @@ -1210,7 +1207,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) const uint256 &bnLimit = Params().ProofOfWorkLimit(); // Testnet has min-difficulty blocks // after nTargetSpacing*2 time between blocks: - if (TestNet() && nTime > nTargetSpacing*2) + if (Params().AllowMinDifficultyBlocks() && nTime > nTargetSpacing*2) return bnLimit.GetCompact(); uint256 bnResult; @@ -1238,7 +1235,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead // Only change once per interval if ((pindexLast->nHeight+1) % nInterval != 0) { - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) { // Special difficulty rule for testnet: // If the new block's timestamp is more than 2* 10 minutes @@ -1468,7 +1465,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); // Updating time can change work required on testnet: - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) block.nBits = GetNextWorkRequired(pindexPrev, &block); } @@ -1898,6 +1895,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C for (unsigned int i = 0; i < block.vtx.size(); i++) g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block); + // Watch for changes to the previous coinbase transaction. + static uint256 hashPrevBestCoinBase; + g_signals.UpdatedTransaction(hashPrevBestCoinBase); + hashPrevBestCoinBase = block.GetTxHash(0); + return true; } @@ -2027,11 +2029,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { return false; // Remove conflicting transactions from the mempool. list<CTransaction> txConflicted; - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - list<CTransaction> unused; - mempool.remove(tx, unused); - mempool.removeConflicts(tx, txConflicted); - } + mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted); mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); @@ -2047,23 +2045,17 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { return true; } -// Make chainMostWork correspond to the chain with the most work in it, that isn't +// Return the tip of the chain with the most work in it, that isn't // known to be invalid (it's however far from certain to be valid). -void static FindMostWorkChain() { - CBlockIndex *pindexNew = NULL; - - // In case the current best is invalid, do not consider it. - while (chainMostWork.Tip() && (chainMostWork.Tip()->nStatus & BLOCK_FAILED_MASK)) { - setBlockIndexValid.erase(chainMostWork.Tip()); - chainMostWork.SetTip(chainMostWork.Tip()->pprev); - } - +static CBlockIndex* FindMostWorkChain() { do { + CBlockIndex *pindexNew = NULL; + // Find the best candidate header. { std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexValid.rbegin(); if (it == setBlockIndexValid.rend()) - return; + return NULL; pindexNew = *it; } @@ -2087,70 +2079,111 @@ void static FindMostWorkChain() { } pindexTest = pindexTest->pprev; } - if (fInvalidAncestor) - continue; - - break; + if (!fInvalidAncestor) + return pindexNew; } while(true); - - // Check whether it's actually an improvement. - if (chainMostWork.Tip() && !CBlockIndexWorkComparator()(chainMostWork.Tip(), pindexNew)) - return; - - // We have a new best. - chainMostWork.SetTip(pindexNew); } -// Try to activate to the most-work chain (thereby connecting it). -bool ActivateBestChain(CValidationState &state) { - LOCK(cs_main); +// Try to make some progress towards making pindexMostWork the active block. +static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) { + AssertLockHeld(cs_main); + bool fInvalidFound = false; CBlockIndex *pindexOldTip = chainActive.Tip(); - bool fComplete = false; - while (!fComplete) { - FindMostWorkChain(); - fComplete = true; + CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); - // Check whether we have something to do. - if (chainMostWork.Tip() == NULL) break; + // Disconnect active blocks which are no longer in the best chain. + while (chainActive.Tip() && chainActive.Tip() != pindexFork) { + if (!DisconnectTip(state)) + return false; + } - // Disconnect active blocks which are no longer in the best chain. - while (chainActive.Tip() && !chainMostWork.Contains(chainActive.Tip())) { - if (!DisconnectTip(state)) - return false; - } + // Build list of new blocks to connect. + std::vector<CBlockIndex*> vpindexToConnect; + vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1)); + while (pindexMostWork && pindexMostWork != pindexFork) { + vpindexToConnect.push_back(pindexMostWork); + pindexMostWork = pindexMostWork->pprev; + } - // Connect new blocks. - while (!chainActive.Contains(chainMostWork.Tip())) { - CBlockIndex *pindexConnect = chainMostWork[chainActive.Height() + 1]; - if (!ConnectTip(state, pindexConnect)) { - if (state.IsInvalid()) { - // The block violates a consensus rule. - if (!state.CorruptionPossible()) - InvalidChainFound(chainMostWork.Tip()); - fComplete = false; - state = CValidationState(); - break; - } else { - // A system error occurred (disk space, database error, ...). - return false; - } + // Connect new blocks. + BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { + if (!ConnectTip(state, pindexConnect)) { + if (state.IsInvalid()) { + // The block violates a consensus rule. + if (!state.CorruptionPossible()) + InvalidChainFound(vpindexToConnect.back()); + state = CValidationState(); + fInvalidFound = true; + break; + } else { + // A system error occurred (disk space, database error, ...). + return false; + } + } else { + if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { + // We're in a better position than we were. Return temporarily to release the lock. + break; } } } - if (chainActive.Tip() != pindexOldTip) { - std::string strCmd = GetArg("-blocknotify", ""); - if (!IsInitialBlockDownload() && !strCmd.empty()) + // Callbacks/notifications for a new best chain. + if (fInvalidFound) + CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); + else + CheckForkWarningConditions(); + + if (!pblocktree->Flush()) + return state.Abort(_("Failed to sync block index")); + + return true; +} + +bool ActivateBestChain(CValidationState &state) { + CBlockIndex *pindexNewTip = NULL; + CBlockIndex *pindexMostWork = NULL; + do { + boost::this_thread::interruption_point(); + + bool fInitialDownload; { - boost::replace_all(strCmd, "%s", chainActive.Tip()->GetBlockHash().GetHex()); - boost::thread t(runCommand, strCmd); // thread runs free + LOCK(cs_main); + pindexMostWork = FindMostWorkChain(); + + // Whether we have anything to do at all. + if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) + return true; + + if (!ActivateBestChainStep(state, pindexMostWork)) + return false; + + pindexNewTip = chainActive.Tip(); + fInitialDownload = IsInitialBlockDownload(); } - } + // When we reach this point, we switched to a new tip (stored in pindexNewTip). + + // Notifications/callbacks that can run without cs_main + if (!fInitialDownload) { + uint256 hashNewTip = pindexNewTip->GetBlockHash(); + // Relay inventory, but don't relay old inventory during initial block download. + int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); + + std::string strCmd = GetArg("-blocknotify", ""); + if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free + } + } + uiInterface.NotifyBlocksChanged(); + } while(pindexMostWork != chainActive.Tip()); return true; } - CBlockIndex* AddToBlockIndex(CBlockHeader& block) { // Check for duplicate @@ -2210,26 +2243,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew))) return state.Abort(_("Failed to write block index")); - // New best? - if (!ActivateBestChain(state)) - return false; - - LOCK(cs_main); - if (pindexNew == chainActive.Tip()) - { - // Clear fork warning if its no longer applicable - CheckForkWarningConditions(); - // Notify UI to display prev block's coinbase if it was ours - static uint256 hashPrevBestCoinBase; - g_signals.UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = block.GetTxHash(0); - } else - CheckForkWarningConditionsOnNewFork(pindexNew); - - if (!pblocktree->Flush()) - return state.Abort(_("Failed to sync block index")); - - uiInterface.NotifyBlocksChanged(); return true; } @@ -2469,14 +2482,11 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex 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 (block.nVersion < 2) + if (block.nVersion < 2 && + CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) { - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) - { - return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), - REJECT_OBSOLETE, "bad-version"); - } + return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), + REJECT_OBSOLETE, "bad-version"); } } @@ -2506,7 +2516,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, } int nHeight = pindex->nHeight; - uint256 hash = pindex->GetBlockHash(); // Check that all transactions are finalized BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -2517,19 +2526,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (block.nVersion >= 2) + // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): + if (block.nVersion >= 2 && + CBlockIndex::IsSuperMajority(2, pindex->pprev, Params().EnforceBlockUpgradeMajority())) { - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 750, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 51, 100))) - { - CScript expect = CScript() << nHeight; - if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || - !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { - pindex->nStatus |= BLOCK_FAILED_VALID; - return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), - REJECT_INVALID, "bad-cb-height"); - } + CScript expect = CScript() << nHeight; + if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { + pindex->nStatus |= BLOCK_FAILED_VALID; + return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), REJECT_INVALID, "bad-cb-height"); } } @@ -2550,21 +2555,12 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return state.Abort(_("System error: ") + e.what()); } - // Relay inventory, but don't relay old inventory during initial block download - int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); - if (chainActive.Tip()->GetBlockHash() == hash) - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) - pnode->PushInventory(CInv(MSG_BLOCK, hash)); - } - return true; } -bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck) +bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired) { + unsigned int nToCheck = Params().ToCheckBlockUpgradeMajority(); unsigned int nFound = 0; for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++) { @@ -2589,10 +2585,11 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd) bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) { - AssertLockHeld(cs_main); - // Check for duplicate uint256 hash = pblock->GetHash(); + + { + LOCK(cs_main); if (mapBlockIndex.count(hash)) return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString()), 0, "duplicate"); if (mapOrphanBlocks.count(hash)) @@ -2661,7 +2658,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl mapOrphanBlocksByPrev.erase(hashPrev); } - LogPrintf("ProcessBlock: ACCEPTED\n"); + } + + if (!ActivateBestChain(state)) + return error("ProcessBlock() : ActivateBestChain failed"); + return true; } @@ -2968,7 +2969,17 @@ bool static LoadBlockIndexDB() return true; } -bool VerifyDB(int nCheckLevel, int nCheckDepth) +CVerifyDB::CVerifyDB() +{ + uiInterface.ShowProgress(_("Verifying blocks..."), 0); +} + +CVerifyDB::~CVerifyDB() +{ + uiInterface.ShowProgress("", 100); +} + +bool CVerifyDB::VerifyDB(int nCheckLevel, int nCheckDepth) { LOCK(cs_main); if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) @@ -2989,6 +3000,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); if (pindex->nHeight < chainActive.Height()-nCheckDepth) break; CBlock block; @@ -3028,6 +3040,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) CBlockIndex *pindex = pindexState; while (pindex != chainActive.Tip()) { boost::this_thread::interruption_point(); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); pindex = chainActive.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex)) @@ -3085,6 +3098,8 @@ bool InitBlockIndex() { CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); + if (!ActivateBestChain(state)) + return error("LoadBlockIndex() : genesis block cannot be activated"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); } @@ -3214,7 +3229,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process block if (nBlockPos >= nStartByte) { - LOCK(cs_main); if (dbp) dbp->nPos = nBlockPos; CValidationState state; @@ -3378,7 +3392,8 @@ void static ProcessGetData(CNode* pfrom) { // Send block from disk CBlock block; - assert(ReadBlockFromDisk(block, (*mi).second)); + if (!ReadBlockFromDisk(block, (*mi).second)) + assert(!"cannot load block from disk"); if (inv.type == MSG_BLOCK) pfrom->PushMessage("block", block); else // MSG_FILTERED_BLOCK) @@ -3550,7 +3565,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (!pfrom->fInbound) { // Advertise our address - if (!fNoListen && !IsInitialBlockDownload()) + if (fListen && !IsInitialBlockDownload()) { CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) @@ -3902,10 +3917,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CInv inv(MSG_BLOCK, block.GetHash()); pfrom->AddInventoryKnown(inv); - LOCK(cs_main); - // Remember who we got this block from. - mapBlockSource[inv.hash] = pfrom->GetId(); - MarkBlockAsReceived(inv.hash, pfrom->GetId()); + { + LOCK(cs_main); + // Remember who we got this block from. + mapBlockSource[inv.hash] = pfrom->GetId(); + MarkBlockAsReceived(inv.hash, pfrom->GetId()); + } CValidationState state; ProcessBlock(state, pfrom, &block); @@ -4318,7 +4335,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pnode->setAddrKnown.clear(); // Rebroadcast our address - if (!fNoListen) + if (fListen) { CAddress addr = GetLocalAddress(&pnode->addr); if (addr.IsRoutable()) diff --git a/src/main.h b/src/main.h index 8a05eb60d..d907bdbaf 100644 --- a/src/main.h +++ b/src/main.h @@ -45,8 +45,8 @@ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; 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; -/** The maximum number of orphan blocks kept in memory */ -static const unsigned int MAX_ORPHAN_BLOCKS = 750; +/** Default for -maxorphanblocks, maximum number of orphan blocks kept in memory */ +static const unsigned int DEFAULT_MAX_ORPHAN_BLOCKS = 750; /** 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) */ @@ -66,12 +66,6 @@ static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 128; /** Timeout in seconds before considering a block download peer unresponsive. */ static const unsigned int BLOCK_DOWNLOAD_TIMEOUT = 60; -#ifdef USE_UPNP -static const int fHaveUPnP = true; -#else -static const int fHaveUPnP = false; -#endif - /** "reject" message codes **/ static const unsigned char REJECT_MALFORMED = 0x01; static const unsigned char REJECT_INVALID = 0x10; @@ -144,8 +138,6 @@ bool InitBlockIndex(); 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(); /** Process protocol messages received from a given node */ @@ -294,13 +286,6 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx); unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs); -inline bool AllowFree(double dPriority) -{ - // Large (in bytes) low-priority (new, small-coin) transactions - // need a fee. - return dPriority > COIN * 144 / 250; -} - // 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. @@ -850,10 +835,11 @@ public: /** * Returns true if there are nRequired or more blocks of minVersion or above - * in the last nToCheck blocks, starting at pstart and going backwards. + * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart + * and going backwards. */ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, - unsigned int nRequired, unsigned int nToCheck); + unsigned int nRequired); std::string ToString() const { @@ -1024,6 +1010,15 @@ public: std::string GetRejectReason() const { return strRejectReason; } }; +/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ +class CVerifyDB { +public: + + CVerifyDB(); + ~CVerifyDB(); + bool VerifyDB(int nCheckLevel, int nCheckDepth); +}; + /** An in-memory indexed chain of blocks. */ class CChain { private: @@ -1079,14 +1074,14 @@ public: /** Find the last common block between this chain and a locator. */ CBlockIndex *FindFork(const CBlockLocator &locator) const; + + /** Find the last common block between this chain and a block index entry. */ + CBlockIndex *FindFork(CBlockIndex *pindex) const; }; /** The currently-connected chain of blocks. */ extern CChain chainActive; -/** The currently best known chain of headers (some of which may be invalid). */ -extern CChain chainMostWork; - /** Global variable that points to the active CCoinsView (protected by cs_main) */ extern CCoinsViewCache *pcoinsTip; diff --git a/src/miner.cpp b/src/miner.cpp index 94fc8e388..68abc4a6e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -52,25 +52,30 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit) ((uint32_t*)pstate)[i] = ctx.h[i]; } -// Some explaining would be appreciated +// +// Unconfirmed transactions in the memory pool often depend on other +// transactions in the memory pool. When we select transactions from the +// pool, we select by highest priority or fee rate, so we might consider +// transactions that depend on transactions that aren't yet in the block. +// The COrphan class keeps track of these 'temporary orphans' while +// CreateBlock is figuring out which transactions to include. +// class COrphan { public: const CTransaction* ptx; set<uint256> setDependsOn; + CFeeRate feeRate; double dPriority; - double dFeePerKb; - COrphan(const CTransaction* ptxIn) + COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) { - ptx = ptxIn; - dPriority = dFeePerKb = 0; } void print() const { - LogPrintf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", - ptx->GetHash().ToString(), dPriority, dFeePerKb); + LogPrintf("COrphan(hash=%s, dPriority=%.1f, fee=%s)\n", + ptx->GetHash().ToString(), dPriority, feeRate.ToString()); BOOST_FOREACH(uint256 hash, setDependsOn) LogPrintf(" setDependsOn %s\n", hash.ToString()); } @@ -80,8 +85,8 @@ public: uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; -// We want to sort transactions by priority and fee, so: -typedef boost::tuple<double, double, const CTransaction*> TxPriority; +// We want to sort transactions by priority and fee rate, so: +typedef boost::tuple<double, CFeeRate, const CTransaction*> TxPriority; class TxPriorityCompare { bool byFee; @@ -210,18 +215,15 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); dPriority = tx.ComputePriority(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); + CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); if (porphan) { porphan->dPriority = dPriority; - porphan->dFeePerKb = dFeePerKb; + porphan->feeRate = feeRate; } else - vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &mi->second.GetTx())); + vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx())); } // Collect transactions into block @@ -237,7 +239,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); - double dFeePerKb = vecPriority.front().get<1>(); + CFeeRate feeRate = vecPriority.front().get<1>(); const CTransaction& tx = *(vecPriority.front().get<2>()); std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); @@ -254,7 +256,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) continue; // Skip free transactions if we're past the minimum block size: - if (fSortedByFee && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (fSortedByFee && (feeRate < CTransaction::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritize by fee once past the priority size or we run out of high-priority @@ -298,8 +300,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (fPrintPriority) { - LogPrintf("priority %.1f feeperkb %.1f txid %s\n", - dPriority, dFeePerKb, tx.GetHash().ToString()); + LogPrintf("priority %.1f fee %s txid %s\n", + dPriority, feeRate.ToString(), tx.GetHash().ToString()); } // Add transactions that depend on this one to the priority queue @@ -312,7 +314,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) { - vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); + vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx)); std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); } } @@ -482,22 +484,22 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) LOCK(cs_main); if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) return error("BitcoinMiner : generated block is stale"); + } - // Remove key from key pool - reservekey.KeepKey(); + // Remove key from key pool + reservekey.KeepKey(); - // Track how many getdata requests this block gets - { - LOCK(wallet.cs_wallet); - wallet.mapRequestCount[pblock->GetHash()] = 0; - } - - // Process this block the same as if we had received it from another node - CValidationState state; - if (!ProcessBlock(state, NULL, pblock)) - return error("BitcoinMiner : ProcessBlock, block not accepted"); + // Track how many getdata requests this block gets + { + LOCK(wallet.cs_wallet); + wallet.mapRequestCount[pblock->GetHash()] = 0; } + // Process this block the same as if we had received it from another node + CValidationState state; + if (!ProcessBlock(state, NULL, pblock)) + return error("BitcoinMiner : ProcessBlock, block not accepted"); + return true; } @@ -512,7 +514,7 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nExtraNonce = 0; try { while (true) { - if (Params().NetworkID() != CChainParams::REGTEST) { + if (Params().MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining // on an obsolete chain. In regtest mode we expect to fly solo. while (vNodes.empty()) @@ -580,9 +582,8 @@ void static BitcoinMiner(CWallet *pwallet) CheckWork(pblock, *pwallet, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); - // In regression test mode, stop mining after a block is found. This - // allows developers to controllably generate a block on demand. - if (Params().NetworkID() == CChainParams::REGTEST) + // In regression test mode, stop mining after a block is found. + if (Params().MineBlocksOnDemand()) throw boost::thread_interrupted(); break; @@ -620,7 +621,8 @@ void static BitcoinMiner(CWallet *pwallet) // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); - if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST) + // Regtest mode doesn't require peers + if (vNodes.empty() && Params().MiningRequiresPeers()) break; if (nBlockNonce >= 0xffff0000) break; @@ -632,7 +634,7 @@ void static BitcoinMiner(CWallet *pwallet) // Update nTime every few seconds UpdateTime(*pblock, pindexPrev); nBlockTime = ByteReverse(pblock->nTime); - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: nBlockBits = ByteReverse(pblock->nBits); @@ -652,8 +654,9 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) static boost::thread_group* minerThreads = NULL; if (nThreads < 0) { - if (Params().NetworkID() == CChainParams::REGTEST) - nThreads = 1; + // In regtest threads defaults to 1 + if (Params().DefaultMinerThreads()) + nThreads = Params().DefaultMinerThreads(); else nThreads = boost::thread::hardware_concurrency(); } diff --git a/src/net.cpp b/src/net.cpp index b0e6699ed..479f77c46 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -45,6 +45,7 @@ static const int MAX_OUTBOUND_CONNECTIONS = 8; // Global state variables // bool fDiscover = true; +bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; CCriticalSection cs_mapLocalHost; map<CNetAddr, LocalServiceInfo> mapLocalHost; @@ -96,7 +97,7 @@ unsigned short GetListenPort() // find 'best' local address for a particular peer bool GetLocal(CService& addr, const CNetAddr *paddrPeer) { - if (fNoListen) + if (!fListen) return false; int nBestScore = -1; @@ -105,6 +105,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); extern bool fDiscover; +extern bool fListen; extern uint64_t nLocalServices; extern uint64_t nLocalHostNonce; extern CAddrMan addrman; @@ -129,7 +130,7 @@ struct LocalServiceInfo { }; extern CCriticalSection cs_mapLocalHost; -extern map<CNetAddr, LocalServiceInfo> mapLocalHost; +extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost; class CNodeStats { diff --git a/src/protocol.cpp b/src/protocol.cpp index c77a92f02..87b2f2387 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -5,6 +5,7 @@ #include "protocol.h" +#include "chainparams.h" #include "util.h" #ifndef WIN32 diff --git a/src/protocol.h b/src/protocol.h index e6f105fe5..6de5d05a7 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -10,7 +10,6 @@ #ifndef __INCLUDED_PROTOCOL_H__ #define __INCLUDED_PROTOCOL_H__ -#include "chainparams.h" #include "netbase.h" #include "serialize.h" #include "uint256.h" @@ -19,6 +18,8 @@ #include <stdint.h> #include <string> +#define MESSAGE_START_SIZE 4 + /** Message header. * (4) message start. * (12) command. diff --git a/src/qt/Makefile b/src/qt/Makefile new file mode 100644 index 000000000..b9dcf0c59 --- /dev/null +++ b/src/qt/Makefile @@ -0,0 +1,9 @@ +.PHONY: FORCE +all: FORCE + $(MAKE) -C .. bitcoin_qt test_bitcoin_qt +clean: FORCE + $(MAKE) -C .. bitcoin_qt_clean test_bitcoin_qt_clean +check: FORCE + $(MAKE) -C .. test_bitcoin_qt_check +bitcoin-qt bitcoin-qt.exe: FORCE + $(MAKE) -C .. bitcoin_qt diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am deleted file mode 100644 index 648971bd8..000000000 --- a/src/qt/Makefile.am +++ /dev/null @@ -1,379 +0,0 @@ -include $(top_srcdir)/src/Makefile.include - -AM_CPPFLAGS += -I$(top_srcdir)/src \ - -I$(top_builddir)/src/qt \ - -I$(top_builddir)/src/qt/forms \ - $(PROTOBUF_CFLAGS) \ - $(QR_CFLAGS) -bin_PROGRAMS = bitcoin-qt -noinst_LIBRARIES = libbitcoinqt.a -SUBDIRS = . $(BUILD_TEST_QT) -DIST_SUBDIRS = . test - -# bitcoin qt core # -QT_TS = \ - locale/bitcoin_ach.ts \ - locale/bitcoin_af_ZA.ts \ - locale/bitcoin_ar.ts \ - locale/bitcoin_be_BY.ts \ - locale/bitcoin_bg.ts \ - locale/bitcoin_bs.ts \ - locale/bitcoin_ca_ES.ts \ - locale/bitcoin_ca.ts \ - locale/[email protected] \ - locale/bitcoin_cmn.ts \ - locale/bitcoin_cs.ts \ - locale/bitcoin_cy.ts \ - locale/bitcoin_da.ts \ - locale/bitcoin_de.ts \ - locale/bitcoin_el_GR.ts \ - locale/bitcoin_en.ts \ - locale/bitcoin_eo.ts \ - locale/bitcoin_es_CL.ts \ - locale/bitcoin_es_DO.ts \ - locale/bitcoin_es_MX.ts \ - locale/bitcoin_es.ts \ - locale/bitcoin_es_UY.ts \ - locale/bitcoin_et.ts \ - locale/bitcoin_eu_ES.ts \ - locale/bitcoin_fa_IR.ts \ - locale/bitcoin_fa.ts \ - locale/bitcoin_fi.ts \ - locale/bitcoin_fr_CA.ts \ - locale/bitcoin_fr.ts \ - locale/bitcoin_gl.ts \ - locale/bitcoin_gu_IN.ts \ - locale/bitcoin_he.ts \ - locale/bitcoin_hi_IN.ts \ - locale/bitcoin_hr.ts \ - locale/bitcoin_hu.ts \ - locale/bitcoin_id_ID.ts \ - locale/bitcoin_it.ts \ - locale/bitcoin_ja.ts \ - locale/bitcoin_ka.ts \ - locale/bitcoin_kk_KZ.ts \ - locale/bitcoin_ko_KR.ts \ - locale/bitcoin_ky.ts \ - locale/bitcoin_la.ts \ - locale/bitcoin_lt.ts \ - locale/bitcoin_lv_LV.ts \ - locale/bitcoin_mn.ts \ - locale/bitcoin_ms_MY.ts \ - locale/bitcoin_nb.ts \ - locale/bitcoin_nl.ts \ - locale/bitcoin_pam.ts \ - locale/bitcoin_pl.ts \ - locale/bitcoin_pt_BR.ts \ - locale/bitcoin_pt_PT.ts \ - locale/bitcoin_ro_RO.ts \ - locale/bitcoin_ru.ts \ - locale/bitcoin_sah.ts \ - locale/bitcoin_sk.ts \ - locale/bitcoin_sl_SI.ts \ - locale/bitcoin_sq.ts \ - locale/bitcoin_sr.ts \ - locale/bitcoin_sv.ts \ - locale/bitcoin_th_TH.ts \ - locale/bitcoin_tr.ts \ - locale/bitcoin_uk.ts \ - locale/bitcoin_ur_PK.ts \ - locale/[email protected] \ - locale/bitcoin_vi.ts \ - locale/bitcoin_vi_VN.ts \ - locale/bitcoin_zh_CN.ts \ - locale/bitcoin_zh_HK.ts \ - locale/bitcoin_zh_TW.ts - -QT_FORMS_UI = \ - forms/aboutdialog.ui \ - forms/addressbookpage.ui \ - forms/askpassphrasedialog.ui \ - forms/coincontroldialog.ui \ - forms/editaddressdialog.ui \ - forms/helpmessagedialog.ui \ - forms/intro.ui \ - forms/openuridialog.ui \ - forms/optionsdialog.ui \ - forms/overviewpage.ui \ - forms/receivecoinsdialog.ui \ - forms/receiverequestdialog.ui \ - forms/rpcconsole.ui \ - forms/sendcoinsdialog.ui \ - forms/sendcoinsentry.ui \ - forms/signverifymessagedialog.ui \ - forms/transactiondescdialog.ui - -QT_MOC_CPP = \ - moc_addressbookpage.cpp \ - moc_addresstablemodel.cpp \ - moc_askpassphrasedialog.cpp \ - moc_bitcoinaddressvalidator.cpp \ - moc_bitcoinamountfield.cpp \ - moc_bitcoingui.cpp \ - moc_bitcoinunits.cpp \ - moc_clientmodel.cpp \ - moc_coincontroldialog.cpp \ - moc_coincontroltreewidget.cpp \ - moc_csvmodelwriter.cpp \ - moc_editaddressdialog.cpp \ - moc_guiutil.cpp \ - moc_intro.cpp \ - moc_macdockiconhandler.cpp \ - moc_macnotificationhandler.cpp \ - moc_monitoreddatamapper.cpp \ - moc_notificator.cpp \ - moc_openuridialog.cpp \ - moc_optionsdialog.cpp \ - moc_optionsmodel.cpp \ - moc_overviewpage.cpp \ - moc_paymentserver.cpp \ - moc_qvalidatedlineedit.cpp \ - moc_qvaluecombobox.cpp \ - moc_receivecoinsdialog.cpp \ - moc_receiverequestdialog.cpp \ - moc_recentrequeststablemodel.cpp \ - moc_rpcconsole.cpp \ - moc_sendcoinsdialog.cpp \ - moc_sendcoinsentry.cpp \ - moc_signverifymessagedialog.cpp \ - moc_splashscreen.cpp \ - moc_trafficgraphwidget.cpp \ - moc_transactiondesc.cpp \ - moc_transactiondescdialog.cpp \ - moc_transactionfilterproxy.cpp \ - moc_transactiontablemodel.cpp \ - moc_transactionview.cpp \ - moc_utilitydialog.cpp \ - moc_walletframe.cpp \ - moc_walletmodel.cpp \ - moc_walletview.cpp - -BITCOIN_MM = \ - macdockiconhandler.mm \ - macnotificationhandler.mm - -QT_MOC = \ - bitcoin.moc \ - intro.moc \ - overviewpage.moc \ - rpcconsole.moc - -QT_QRC_CPP = qrc_bitcoin.cpp -QT_QRC = bitcoin.qrc - -PROTOBUF_CC = paymentrequest.pb.cc -PROTOBUF_H = paymentrequest.pb.h -PROTOBUF_PROTO = paymentrequest.proto - -BITCOIN_QT_H = \ - addressbookpage.h \ - addresstablemodel.h \ - askpassphrasedialog.h \ - bitcoinaddressvalidator.h \ - bitcoinamountfield.h \ - bitcoingui.h \ - bitcoinunits.h \ - clientmodel.h \ - coincontroldialog.h \ - coincontroltreewidget.h \ - csvmodelwriter.h \ - editaddressdialog.h \ - guiconstants.h \ - guiutil.h \ - intro.h \ - macdockiconhandler.h \ - macnotificationhandler.h \ - monitoreddatamapper.h \ - notificator.h \ - openuridialog.h \ - optionsdialog.h \ - optionsmodel.h \ - overviewpage.h \ - paymentrequestplus.h \ - paymentserver.h \ - qvalidatedlineedit.h \ - qvaluecombobox.h \ - receivecoinsdialog.h \ - receiverequestdialog.h \ - recentrequeststablemodel.h \ - rpcconsole.h \ - sendcoinsdialog.h \ - sendcoinsentry.h \ - signverifymessagedialog.h \ - splashscreen.h \ - trafficgraphwidget.h \ - transactiondesc.h \ - transactiondescdialog.h \ - transactionfilterproxy.h \ - transactionrecord.h \ - transactiontablemodel.h \ - transactionview.h \ - utilitydialog.h \ - walletframe.h \ - walletmodel.h \ - walletmodeltransaction.h \ - walletview.h \ - winshutdownmonitor.h - -RES_ICONS = \ - res/icons/add.png \ - res/icons/address-book.png \ - res/icons/bitcoin.ico \ - res/icons/bitcoin.png \ - res/icons/bitcoin_testnet.ico \ - res/icons/bitcoin_testnet.png \ - res/icons/clock1.png \ - res/icons/clock2.png \ - res/icons/clock3.png \ - res/icons/clock4.png \ - res/icons/clock5.png \ - res/icons/configure.png \ - res/icons/connect0_16.png \ - res/icons/connect1_16.png \ - res/icons/connect2_16.png \ - res/icons/connect3_16.png \ - res/icons/connect4_16.png \ - res/icons/debugwindow.png \ - res/icons/edit.png \ - res/icons/editcopy.png \ - res/icons/editpaste.png \ - res/icons/export.png \ - res/icons/filesave.png \ - res/icons/history.png \ - res/icons/key.png \ - res/icons/lock_closed.png \ - res/icons/lock_open.png \ - res/icons/overview.png \ - res/icons/qrcode.png \ - res/icons/quit.png \ - res/icons/receive.png \ - res/icons/remove.png \ - res/icons/send.png \ - res/icons/synced.png \ - res/icons/toolbar.png \ - res/icons/toolbar_testnet.png \ - res/icons/transaction0.png \ - res/icons/transaction2.png \ - res/icons/transaction_conflicted.png \ - res/icons/tx_inout.png \ - res/icons/tx_input.png \ - res/icons/tx_output.png \ - res/icons/tx_mined.png - -BITCOIN_QT_CPP = \ - bitcoin.cpp \ - bitcoinaddressvalidator.cpp \ - bitcoinamountfield.cpp \ - bitcoingui.cpp \ - bitcoinunits.cpp \ - clientmodel.cpp \ - csvmodelwriter.cpp \ - guiutil.cpp \ - intro.cpp \ - monitoreddatamapper.cpp \ - notificator.cpp \ - optionsdialog.cpp \ - optionsmodel.cpp \ - qvalidatedlineedit.cpp \ - qvaluecombobox.cpp \ - rpcconsole.cpp \ - splashscreen.cpp \ - trafficgraphwidget.cpp \ - utilitydialog.cpp \ - winshutdownmonitor.cpp - -if ENABLE_WALLET -BITCOIN_QT_CPP += \ - addressbookpage.cpp \ - addresstablemodel.cpp \ - askpassphrasedialog.cpp \ - coincontroldialog.cpp \ - coincontroltreewidget.cpp \ - editaddressdialog.cpp \ - openuridialog.cpp \ - overviewpage.cpp \ - paymentrequestplus.cpp \ - paymentserver.cpp \ - receivecoinsdialog.cpp \ - receiverequestdialog.cpp \ - recentrequeststablemodel.cpp \ - sendcoinsdialog.cpp \ - sendcoinsentry.cpp \ - signverifymessagedialog.cpp \ - transactiondesc.cpp \ - transactiondescdialog.cpp \ - transactionfilterproxy.cpp \ - transactionrecord.cpp \ - transactiontablemodel.cpp \ - transactionview.cpp \ - walletframe.cpp \ - walletmodel.cpp \ - walletmodeltransaction.cpp \ - walletview.cpp -endif - -RES_IMAGES = \ - res/images/about.png \ - res/images/splash.png \ - res/images/splash_testnet.png - -RES_MOVIES = $(wildcard res/movies/spinner-*.png) - -BITCOIN_RC = res/bitcoin-qt-res.rc - -libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \ - -I$(top_srcdir)/src/qt/forms $(QT_DBUS_INCLUDES) -libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \ - $(QT_QRC) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) - -nodist_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \ - $(PROTOBUF_H) $(QT_QRC_CPP) - -BUILT_SOURCES = $(nodist_libbitcoinqt_a_SOURCES) - -#Generating these with a half-written protobuf header leads to wacky results. -#This makes sure it's done. -$(QT_MOC): $(PROTOBUF_H) -$(QT_MOC_CPP): $(PROTOBUF_H) - -# bitcoin-qt binary # -bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \ - -I$(top_srcdir)/src/qt/forms -bitcoin_qt_SOURCES = bitcoin.cpp -if TARGET_DARWIN - bitcoin_qt_SOURCES += $(BITCOIN_MM) -endif -if TARGET_WINDOWS - bitcoin_qt_SOURCES += $(BITCOIN_RC) -endif -bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN_SERVER) -if ENABLE_WALLET -bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) -endif -bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) -bitcoin_qt_LDFLAGS = $(QT_LDFLAGS) - -# forms/foo.h -> forms/ui_foo.h -QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h)))) - -#locale/foo.ts -> locale/foo.qm -QT_QM=$(QT_TS:.ts=.qm) - -.PHONY: FORCE -.SECONDARY: $(QT_QM) - -bitcoinstrings.cpp: FORCE - $(MAKE) -C $(top_srcdir)/src qt/bitcoinstrings.cpp - -translate: bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) - @test -n $(LUPDATE) || echo "lupdate is required for updating translations" - @QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts locale/bitcoin_en.ts - -$(QT_QRC_CPP): $(QT_QRC) $(QT_QM) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H) - @cd $(abs_srcdir); test -f $(RCC) && QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin -o $(abs_builddir)/$@ $< || \ - echo error: could not build $@ - $(SED) -e '/^\*\*.*Created:/d' $@ > [email protected] && mv $@{.n,} - $(SED) -e '/^\*\*.*by:/d' $@ > [email protected] && mv $@{.n,} - -CLEANFILES = $(BUILT_SOURCES) $(QT_QM) $(QT_FORMS_H) *.gcda *.gcno diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 45d7a5288..2be8191eb 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -475,6 +475,7 @@ int main(int argc, char *argv[]) #endif Q_INIT_RESOURCE(bitcoin); + Q_INIT_RESOURCE(bitcoin_locale); BitcoinApplication app(argc, argv); #if QT_VERSION > 0x050100 // Generate high-dpi pixmaps diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index e1c739b02..f38200c7f 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -84,77 +84,4 @@ <file alias="spinner-033">res/movies/spinner-033.png</file> <file alias="spinner-034">res/movies/spinner-034.png</file> </qresource> - <qresource prefix="/translations"> - <file alias="ach">locale/bitcoin_ach.qm</file> - <file alias="af_ZA">locale/bitcoin_af_ZA.qm</file> - <file alias="ar">locale/bitcoin_ar.qm</file> - <file alias="be_BY">locale/bitcoin_be_BY.qm</file> - <file alias="bg">locale/bitcoin_bg.qm</file> - <file alias="bs">locale/bitcoin_bs.qm</file> - <file alias="ca_ES">locale/bitcoin_ca_ES.qm</file> - <file alias="ca">locale/bitcoin_ca.qm</file> - <file alias="ca@valencia">locale/[email protected]</file> - <file alias="cmn">locale/bitcoin_cmn.qm</file> - <file alias="cs">locale/bitcoin_cs.qm</file> - <file alias="cy">locale/bitcoin_cy.qm</file> - <file alias="da">locale/bitcoin_da.qm</file> - <file alias="de">locale/bitcoin_de.qm</file> - <file alias="el_GR">locale/bitcoin_el_GR.qm</file> - <file alias="en">locale/bitcoin_en.qm</file> - <file alias="eo">locale/bitcoin_eo.qm</file> - <file alias="es_CL">locale/bitcoin_es_CL.qm</file> - <file alias="es_DO">locale/bitcoin_es_DO.qm</file> - <file alias="es_MX">locale/bitcoin_es_MX.qm</file> - <file alias="es">locale/bitcoin_es.qm</file> - <file alias="es_UY">locale/bitcoin_es_UY.qm</file> - <file alias="et">locale/bitcoin_et.qm</file> - <file alias="eu_ES">locale/bitcoin_eu_ES.qm</file> - <file alias="fa_IR">locale/bitcoin_fa_IR.qm</file> - <file alias="fa">locale/bitcoin_fa.qm</file> - <file alias="fi">locale/bitcoin_fi.qm</file> - <file alias="fr_CA">locale/bitcoin_fr_CA.qm</file> - <file alias="fr">locale/bitcoin_fr.qm</file> - <file alias="gl">locale/bitcoin_gl.qm</file> - <file alias="gu_IN">locale/bitcoin_gu_IN.qm</file> - <file alias="he">locale/bitcoin_he.qm</file> - <file alias="hi_IN">locale/bitcoin_hi_IN.qm</file> - <file alias="hr">locale/bitcoin_hr.qm</file> - <file alias="hu">locale/bitcoin_hu.qm</file> - <file alias="id_ID">locale/bitcoin_id_ID.qm</file> - <file alias="it">locale/bitcoin_it.qm</file> - <file alias="ja">locale/bitcoin_ja.qm</file> - <file alias="ka">locale/bitcoin_ka.qm</file> - <file alias="kk_KZ">locale/bitcoin_kk_KZ.qm</file> - <file alias="ko_KR">locale/bitcoin_ko_KR.qm</file> - <file alias="ky">locale/bitcoin_ky.qm</file> - <file alias="la">locale/bitcoin_la.qm</file> - <file alias="lt">locale/bitcoin_lt.qm</file> - <file alias="lv_LV">locale/bitcoin_lv_LV.qm</file> - <file alias="mn">locale/bitcoin_mn.qm</file> - <file alias="ms_MY">locale/bitcoin_ms_MY.qm</file> - <file alias="nb">locale/bitcoin_nb.qm</file> - <file alias="nl">locale/bitcoin_nl.qm</file> - <file alias="pam">locale/bitcoin_pam.qm</file> - <file alias="pl">locale/bitcoin_pl.qm</file> - <file alias="pt_BR">locale/bitcoin_pt_BR.qm</file> - <file alias="pt_PT">locale/bitcoin_pt_PT.qm</file> - <file alias="ro_RO">locale/bitcoin_ro_RO.qm</file> - <file alias="ru">locale/bitcoin_ru.qm</file> - <file alias="sah">locale/bitcoin_sah.qm</file> - <file alias="sk">locale/bitcoin_sk.qm</file> - <file alias="sl_SI">locale/bitcoin_sl_SI.qm</file> - <file alias="sq">locale/bitcoin_sq.qm</file> - <file alias="sr">locale/bitcoin_sr.qm</file> - <file alias="sv">locale/bitcoin_sv.qm</file> - <file alias="th_TH">locale/bitcoin_th_TH.qm</file> - <file alias="tr">locale/bitcoin_tr.qm</file> - <file alias="uk">locale/bitcoin_uk.qm</file> - <file alias="ur_PK">locale/bitcoin_ur_PK.qm</file> - <file alias="uz@Cyrl">locale/[email protected]</file> - <file alias="vi">locale/bitcoin_vi.qm</file> - <file alias="vi_VN">locale/bitcoin_vi_VN.qm</file> - <file alias="zh_CN">locale/bitcoin_zh_CN.qm</file> - <file alias="zh_HK">locale/bitcoin_zh_HK.qm</file> - <file alias="zh_TW">locale/bitcoin_zh_TW.qm</file> - </qresource> </RCC> diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc new file mode 100644 index 000000000..b70a10739 --- /dev/null +++ b/src/qt/bitcoin_locale.qrc @@ -0,0 +1,75 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource prefix="/translations"> + <file alias="ach">locale/bitcoin_ach.qm</file> + <file alias="af_ZA">locale/bitcoin_af_ZA.qm</file> + <file alias="ar">locale/bitcoin_ar.qm</file> + <file alias="be_BY">locale/bitcoin_be_BY.qm</file> + <file alias="bg">locale/bitcoin_bg.qm</file> + <file alias="bs">locale/bitcoin_bs.qm</file> + <file alias="ca_ES">locale/bitcoin_ca_ES.qm</file> + <file alias="ca">locale/bitcoin_ca.qm</file> + <file alias="ca@valencia">locale/[email protected]</file> + <file alias="cmn">locale/bitcoin_cmn.qm</file> + <file alias="cs">locale/bitcoin_cs.qm</file> + <file alias="cy">locale/bitcoin_cy.qm</file> + <file alias="da">locale/bitcoin_da.qm</file> + <file alias="de">locale/bitcoin_de.qm</file> + <file alias="el_GR">locale/bitcoin_el_GR.qm</file> + <file alias="en">locale/bitcoin_en.qm</file> + <file alias="eo">locale/bitcoin_eo.qm</file> + <file alias="es_CL">locale/bitcoin_es_CL.qm</file> + <file alias="es_DO">locale/bitcoin_es_DO.qm</file> + <file alias="es_MX">locale/bitcoin_es_MX.qm</file> + <file alias="es">locale/bitcoin_es.qm</file> + <file alias="es_UY">locale/bitcoin_es_UY.qm</file> + <file alias="et">locale/bitcoin_et.qm</file> + <file alias="eu_ES">locale/bitcoin_eu_ES.qm</file> + <file alias="fa_IR">locale/bitcoin_fa_IR.qm</file> + <file alias="fa">locale/bitcoin_fa.qm</file> + <file alias="fi">locale/bitcoin_fi.qm</file> + <file alias="fr_CA">locale/bitcoin_fr_CA.qm</file> + <file alias="fr">locale/bitcoin_fr.qm</file> + <file alias="gl">locale/bitcoin_gl.qm</file> + <file alias="gu_IN">locale/bitcoin_gu_IN.qm</file> + <file alias="he">locale/bitcoin_he.qm</file> + <file alias="hi_IN">locale/bitcoin_hi_IN.qm</file> + <file alias="hr">locale/bitcoin_hr.qm</file> + <file alias="hu">locale/bitcoin_hu.qm</file> + <file alias="id_ID">locale/bitcoin_id_ID.qm</file> + <file alias="it">locale/bitcoin_it.qm</file> + <file alias="ja">locale/bitcoin_ja.qm</file> + <file alias="ka">locale/bitcoin_ka.qm</file> + <file alias="kk_KZ">locale/bitcoin_kk_KZ.qm</file> + <file alias="ko_KR">locale/bitcoin_ko_KR.qm</file> + <file alias="ky">locale/bitcoin_ky.qm</file> + <file alias="la">locale/bitcoin_la.qm</file> + <file alias="lt">locale/bitcoin_lt.qm</file> + <file alias="lv_LV">locale/bitcoin_lv_LV.qm</file> + <file alias="mn">locale/bitcoin_mn.qm</file> + <file alias="ms_MY">locale/bitcoin_ms_MY.qm</file> + <file alias="nb">locale/bitcoin_nb.qm</file> + <file alias="nl">locale/bitcoin_nl.qm</file> + <file alias="pam">locale/bitcoin_pam.qm</file> + <file alias="pl">locale/bitcoin_pl.qm</file> + <file alias="pt_BR">locale/bitcoin_pt_BR.qm</file> + <file alias="pt_PT">locale/bitcoin_pt_PT.qm</file> + <file alias="ro_RO">locale/bitcoin_ro_RO.qm</file> + <file alias="ru">locale/bitcoin_ru.qm</file> + <file alias="sah">locale/bitcoin_sah.qm</file> + <file alias="sk">locale/bitcoin_sk.qm</file> + <file alias="sl_SI">locale/bitcoin_sl_SI.qm</file> + <file alias="sq">locale/bitcoin_sq.qm</file> + <file alias="sr">locale/bitcoin_sr.qm</file> + <file alias="sv">locale/bitcoin_sv.qm</file> + <file alias="th_TH">locale/bitcoin_th_TH.qm</file> + <file alias="tr">locale/bitcoin_tr.qm</file> + <file alias="uk">locale/bitcoin_uk.qm</file> + <file alias="ur_PK">locale/bitcoin_ur_PK.qm</file> + <file alias="uz@Cyrl">locale/[email protected]</file> + <file alias="vi">locale/bitcoin_vi.qm</file> + <file alias="vi_VN">locale/bitcoin_vi_VN.qm</file> + <file alias="zh_CN">locale/bitcoin_zh_CN.qm</file> + <file alias="zh_HK">locale/bitcoin_zh_HK.qm</file> + <file alias="zh_TW">locale/bitcoin_zh_TW.qm</file> + </qresource> +</RCC> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 68ae8b466..3469f990a 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -40,6 +40,7 @@ #include <QMessageBox> #include <QMimeData> #include <QProgressBar> +#include <QProgressDialog> #include <QSettings> #include <QStackedWidget> #include <QStatusBar> @@ -409,6 +410,9 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // Receive and report messages from client model connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); + // Show progress dialog + connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); + rpcConsole->setClientModel(clientModel); #ifdef ENABLE_WALLET if(walletFrame) @@ -949,6 +953,29 @@ void BitcoinGUI::detectShutdown() } } +void BitcoinGUI::showProgress(const QString &title, int nProgress) +{ + if (nProgress == 0) + { + progressDialog = new QProgressDialog(title, "", 0, 100); + progressDialog->setWindowModality(Qt::ApplicationModal); + progressDialog->setMinimumDuration(0); + progressDialog->setCancelButton(0); + progressDialog->setAutoClose(false); + progressDialog->setValue(0); + } + else if (nProgress == 100) + { + if (progressDialog) + { + progressDialog->close(); + progressDialog->deleteLater(); + } + } + else if (progressDialog) + progressDialog->setValue(nProgress); +} + static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style) { bool modal = (style & CClientUIInterface::MODAL); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index b4675b95a..275fa35f3 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -26,6 +26,7 @@ QT_BEGIN_NAMESPACE class QAction; class QLabel; class QProgressBar; +class QProgressDialog; QT_END_NAMESPACE /** @@ -73,6 +74,7 @@ private: QLabel *labelBlocksIcon; QLabel *progressBarLabel; QProgressBar *progressBar; + QProgressDialog *progressDialog; QMenuBar *appMenuBar; QAction *overviewAction; @@ -191,6 +193,9 @@ private slots: /** called by a timer to check if fRequestShutdown has been set **/ void detectShutdown(); + + /** Show progress dialog e.g. for verifychain */ + void showProgress(const QString &title, int nProgress); }; #endif // BITCOINGUI_H diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index d1f68ebd2..403b03378 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -5,6 +5,7 @@ #include "clientmodel.h" #include "guiconstants.h" +#include "peertablemodel.h" #include "alert.h" #include "chainparams.h" @@ -22,11 +23,14 @@ static const int64_t nClientStartupTime = GetTime(); ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : - QObject(parent), optionsModel(optionsModel), + QObject(parent), + optionsModel(optionsModel), + peerTableModel(0), cachedNumBlocks(0), cachedReindexing(0), cachedImporting(0), numBlocksAtStartup(-1), pollTimer(0) { + peerTableModel = new PeerTableModel(this); pollTimer = new QTimer(this); connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); pollTimer->start(MODEL_UPDATE_DELAY); @@ -173,6 +177,11 @@ OptionsModel *ClientModel::getOptionsModel() return optionsModel; } +PeerTableModel *ClientModel::getPeerTableModel() +{ + return peerTableModel; +} + QString ClientModel::formatFullVersion() const { return QString::fromStdString(FormatFullVersion()); @@ -199,6 +208,14 @@ QString ClientModel::formatClientStartupTime() const } // Handlers for core signals +static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress) +{ + // emits signal "showProgress" + QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(title)), + Q_ARG(int, nProgress)); +} + static void NotifyBlocksChanged(ClientModel *clientmodel) { // This notification is too frequent. Don't trigger a signal. @@ -223,6 +240,7 @@ static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, Ch void ClientModel::subscribeToCoreSignals() { // Connect signals to client + uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this)); uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); @@ -231,6 +249,7 @@ void ClientModel::subscribeToCoreSignals() void ClientModel::unsubscribeFromCoreSignals() { // Disconnect signals from client + uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index cab853d92..9c9a35b65 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -9,6 +9,7 @@ class AddressTableModel; class OptionsModel; +class PeerTableModel; class TransactionTableModel; class CWallet; @@ -42,6 +43,7 @@ public: ~ClientModel(); OptionsModel *getOptionsModel(); + PeerTableModel *getPeerTableModel(); //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; @@ -71,6 +73,7 @@ public: private: OptionsModel *optionsModel; + PeerTableModel *peerTableModel; int cachedNumBlocks; bool cachedReindexing; @@ -92,6 +95,9 @@ signals: //! Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); + // Show progress dialog e.g. for verifychain + void showProgress(const QString &title, int nProgress); + public slots: void updateTimer(); void updateNumConnections(int numConnections); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index dc9d2afe2..42d6da7d3 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -71,7 +71,7 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) : 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 *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity())); @@ -309,7 +309,7 @@ void CoinControlDialog::clipboardPriority() GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); } -// copy label "Low output" to clipboard +// copy label "Dust" to clipboard void CoinControlDialog::clipboardLowOutput() { GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text()); @@ -439,7 +439,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // nPayAmount qint64 nPayAmount = 0; - bool fLowOutput = false; bool fDust = false; CTransaction txDummy; foreach(const qint64 &amount, CoinControlDialog::payAmounts) @@ -448,12 +447,9 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) if (amount > 0) { - if (amount < CENT) - fLowOutput = true; - CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0)); txDummy.vout.push_back(txout); - if (txout.IsDust(CTransaction::nMinRelayTxFee)) + if (txout.IsDust(CTransaction::minRelayTxFee)) fDust = true; } } @@ -525,7 +521,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority); // Fee - int64_t nFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); + int64_t nFee = payTxFee.GetFee(nBytes); // Min Fee int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND); @@ -536,26 +532,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { nChange = nAmount - nPayFee - nPayAmount; - // 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<unsigned char>(24, 0)); - if (txout.IsDust(CTransaction::nMinRelayTxFee)) + if (txout.IsDust(CTransaction::minRelayTxFee)) { nPayFee += nChange; nChange = 0; @@ -586,7 +567,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput"); QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange"); - // enable/disable "low output" and "change" + // enable/disable "dust" and "change" dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0); dialog->findChild<QLabel *>("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0); dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0); @@ -599,39 +580,31 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) 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 + l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change // turn labels "red" l5->setStyleSheet((nBytes >= 1000) ? "color:red;" : ""); // Bytes >= 1000 l6->setStyleSheet((dPriority > 0 && !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 + l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes" // tool tips QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />"; - toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />"; + toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())) + "<br /><br />"; toolTip1 += tr("Can vary +/- 1 byte per input."); QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />"; toolTip2 += tr("This label turns red, if the priority is smaller than \"medium\".") + "<br /><br />"; - toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)); - - QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />"; - toolTip3 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />"; - toolTip3 += tr("Amounts below 0.546 times the minimum relay fee are shown as dust."); + toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())); - QString toolTip4 = tr("This label turns red, if the change is smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />"; - toolTip4 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)); + QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minRelayTxFee.GetFee(546))); l5->setToolTip(toolTip1); l6->setToolTip(toolTip2); l7->setToolTip(toolTip3); - l8->setToolTip(toolTip4); dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip()); dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip()); dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip()); - dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip()); // Insufficient funds QLabel *label = dialog->findChild<QLabel *>("labelCoinControlInsuffFunds"); diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui index cd1c0ffa1..67ea3a9d8 100644 --- a/src/qt/forms/coincontroldialog.ui +++ b/src/qt/forms/coincontroldialog.ui @@ -225,7 +225,7 @@ </font> </property> <property name="text"> - <string>Low Output:</string> + <string>Dust:</string> </property> </widget> </item> diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index fcb6bb60b..1e574e852 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -113,13 +113,39 @@ </widget> </item> <item row="4" column="0"> + <widget class="QLabel" name="label_berkeleyDBVersion"> + <property name="text"> + <string>Using BerkeleyDB version</string> + </property> + <property name="indent"> + <number>10</number> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="berkeleyDBVersion"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="5" column="0"> <widget class="QLabel" name="label_12"> <property name="text"> <string>Build date</string> </property> </widget> </item> - <item row="4" column="1"> + <item row="5" column="1"> <widget class="QLabel" name="buildDate"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -135,14 +161,14 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="label_13"> <property name="text"> <string>Startup time</string> </property> </widget> </item> - <item row="5" column="1"> + <item row="6" column="1"> <widget class="QLabel" name="startupTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -158,7 +184,7 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="label_11"> <property name="font"> <font> @@ -171,14 +197,14 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="8" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> <string>Name</string> </property> </widget> </item> - <item row="7" column="1"> + <item row="8" column="1"> <widget class="QLabel" name="networkName"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -194,14 +220,14 @@ </property> </widget> </item> - <item row="8" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_7"> <property name="text"> <string>Number of connections</string> </property> </widget> </item> - <item row="8" column="1"> + <item row="9" column="1"> <widget class="QLabel" name="numberOfConnections"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -217,7 +243,7 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_10"> <property name="font"> <font> @@ -230,14 +256,14 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Current number of blocks</string> </property> </widget> </item> - <item row="10" column="1"> + <item row="11" column="1"> <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -253,14 +279,14 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Last block time</string> </property> </widget> </item> - <item row="11" column="1"> + <item row="12" column="1"> <widget class="QLabel" name="lastBlockTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -276,7 +302,7 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="13" column="0"> <spacer name="verticalSpacer_2"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -289,7 +315,7 @@ </property> </spacer> </item> - <item row="13" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="labelDebugLogfile"> <property name="font"> <font> @@ -302,7 +328,7 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="15" column="0"> <widget class="QPushButton" name="openDebugLogfileButton"> <property name="toolTip"> <string>Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files.</string> @@ -315,7 +341,7 @@ </property> </widget> </item> - <item row="15" column="0"> + <item row="16" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -652,6 +678,281 @@ </item> </layout> </widget> + <widget class="QWidget" name="tab_peers"> + <attribute name="title"> + <string>&Peers</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="1"> + <widget class="QLabel" name="peerHeading"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Select a peer to view detailed information.</string> + </property> + <property name="margin"> + <number>3</number> + </property> + </widget> + </item> + <item row="0" column="0" rowspan="2"> + <widget class="QTableView" name="peerWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QWidget" name="detailWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="leftMargin"> + <number>3</number> + </property> + <item row="12" column="0"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>Version:</string> + </property> + </widget> + </item> + <item row="11" column="1"> + <widget class="QLabel" name="peerPingTime"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_19"> + <property name="text"> + <string>Last Receive:</string> + </property> + </widget> + </item> + <item row="14" column="0"> + <widget class="QLabel" name="label_28"> + <property name="text"> + <string>User Agent:</string> + </property> + </widget> + </item> + <item row="12" column="1"> + <widget class="QLabel" name="peerVersion"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QLabel" name="peerConnTime"> + <property name="minimumSize"> + <size> + <width>160</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="11" column="0"> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>Ping Time:</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLabel" name="peerLastRecv"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="label_22"> + <property name="text"> + <string>Connection Time:</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLabel" name="peerBytesSent"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="14" column="1"> + <widget class="QLabel" name="peerSubversion"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="15" column="0"> + <widget class="QLabel" name="label_29"> + <property name="text"> + <string>Starting Height:</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QLabel" name="peerBytesRecv"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_18"> + <property name="text"> + <string>Bytes Sent:</string> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>Bytes Received:</string> + </property> + </widget> + </item> + <item row="15" column="1"> + <widget class="QLabel" name="peerHeight"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="16" column="0"> + <widget class="QLabel" name="label_24"> + <property name="text"> + <string>Ban Score:</string> + </property> + </widget> + </item> + <item row="16" column="1"> + <widget class="QLabel" name="peerBanScore"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="17" column="0"> + <widget class="QLabel" name="label_23"> + <property name="text"> + <string>Direction:</string> + </property> + </widget> + </item> + <item row="17" column="1"> + <widget class="QLabel" name="peerDirection"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="19" column="0"> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>Sync Node:</string> + </property> + </widget> + </item> + <item row="19" column="1"> + <widget class="QLabel" name="peerSyncNode"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>Last Send:</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Services:</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_27"> + <property name="text"> + <string>IP Address/port:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="peerLastSend"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="peerServices"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="peerAddr"> + <property name="text"> + <string>N/A</string> + </property> + </widget> + </item> + <item row="20" column="0"> + <widget class="QWidget" name="widget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> </widget> </item> </layout> diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 4cb1670c7..a631b0467 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -417,7 +417,7 @@ </font> </property> <property name="text"> - <string>Low Output:</string> + <string>Dust:</string> </property> </widget> </item> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 183fcac4a..4fe98251d 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -11,6 +11,7 @@ #include "core.h" #include "init.h" +#include "protocol.h" #include "util.h" #ifdef WIN32 @@ -209,7 +210,7 @@ bool isDust(const QString& address, qint64 amount) CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); CScript script; script.SetDestination(dest); CTxOut txOut(amount, script); - return txOut.IsDust(CTransaction::nMinRelayTxFee); + return txOut.IsDust(CTransaction::minRelayTxFee); } QString HtmlEscape(const QString& str, bool fMultiLine) @@ -754,4 +755,50 @@ QString boostPathToQString(const boost::filesystem::path &path) } #endif +QString formatDurationStr(int secs) +{ + QStringList strList; + int days = secs / 86400; + int hours = (secs % 86400) / 3600; + int mins = (secs % 3600) / 60; + int seconds = secs % 60; + + if (days) + strList.append(QString(QObject::tr("%1 d")).arg(days)); + if (hours) + strList.append(QString(QObject::tr("%1 h")).arg(hours)); + if (mins) + strList.append(QString(QObject::tr("%1 m")).arg(mins)); + if (seconds || (!days && !hours && !mins)) + strList.append(QString(QObject::tr("%1 s")).arg(seconds)); + + return strList.join(" "); +} + +QString formatServicesStr(uint64_t mask) +{ + QStringList strList; + + // Just scan the last 8 bits for now. + for (int i = 0; i < 8; i++) { + uint64_t check = 1 << i; + if (mask & check) + { + switch (check) + { + case NODE_NETWORK: + strList.append(QObject::tr("NETWORK")); + break; + default: + strList.append(QString("%1[%2]").arg(QObject::tr("UNKNOWN")).arg(check)); + } + } + } + + if (strList.size()) + return strList.join(" & "); + else + return QObject::tr("None"); +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 4f9416d1a..45c78b4e1 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -173,6 +173,11 @@ namespace GUIUtil /* Convert OS specific boost path to QString through UTF-8 */ QString boostPathToQString(const boost::filesystem::path &path); + /* Convert seconds into a QString with days, hours, mins, secs */ + QString formatDurationStr(int secs); + + /* Format CNodeStats.nServices bitmask into a user-readable string */ + QString formatServicesStr(uint64_t mask); } // namespace GUIUtil #endif // GUIUTIL_H diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 687947e3b..e957a0088 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -3,11 +3,11 @@ <name>AboutDialog</name> <message> <source>About Bitcoin Core</source> - <translation type="unfinished"/> + <translation>Σχετικά με το Bitcoin Core</translation> </message> <message> <source><b>Bitcoin Core</b> version</source> - <translation type="unfinished"/> + <translation><b>Bitcoin Core</b> έκδοση</translation> </message> <message> <source> @@ -29,11 +29,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>The Bitcoin Core developers</source> - <translation type="unfinished"/> + <translation>Οι προγραμματιστές του Bitcoin Core</translation> </message> <message> <source>(%1-bit)</source> - <translation type="unfinished"/> + <translation>(%1-bit)</translation> </message> </context> <context> @@ -128,11 +128,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Exporting Failed</source> - <translation type="unfinished"/> + <translation>Η εξαγωγή απέτυχε</translation> </message> <message> <source>There was an error trying to save the address list to %1.</source> - <translation type="unfinished"/> + <translation>Παρουσιάστηκε σφάλμα κατά την αποθήκευση της λίστας πορτοφολιών στο %1.</translation> </message> </context> <context> @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&About Bitcoin Core</source> - <translation type="unfinished"/> + <translation>&Σχετικά με το Bitcoin Core</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> @@ -494,11 +494,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>%1 and %2</source> - <translation type="unfinished"/> + <translation>%1 και %2</translation> </message> <message numerus="yes"> <source>%n year(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>%n έτος</numerusform><numerusform>%n έτη</numerusform></translation> </message> <message> <source>%1 behind</source> @@ -608,11 +608,11 @@ Address: %4 </message> <message> <source>Change:</source> - <translation type="unfinished"/> + <translation>Ρέστα:</translation> </message> <message> <source>(un)select all</source> - <translation type="unfinished"/> + <translation>(από)επιλογή όλων</translation> </message> <message> <source>Tree mode</source> @@ -672,7 +672,7 @@ Address: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>Αντιγραφή ποσότητας</translation> </message> <message> <source>Copy fee</source> @@ -684,11 +684,11 @@ Address: %4 </message> <message> <source>Copy bytes</source> - <translation type="unfinished"/> + <translation>Αντιγραφή των byte</translation> </message> <message> <source>Copy priority</source> - <translation type="unfinished"/> + <translation>Αντιγραφή προτεραιότητας</translation> </message> <message> <source>Copy low output</source> @@ -696,51 +696,51 @@ Address: %4 </message> <message> <source>Copy change</source> - <translation type="unfinished"/> + <translation>Αντιγραφή των ρέστων</translation> </message> <message> <source>highest</source> - <translation type="unfinished"/> + <translation>ύψιστη</translation> </message> <message> <source>higher</source> - <translation type="unfinished"/> + <translation>υψηλότερη</translation> </message> <message> <source>high</source> - <translation type="unfinished"/> + <translation>ψηλή</translation> </message> <message> <source>medium-high</source> - <translation type="unfinished"/> + <translation>μεσαία-ψηλή</translation> </message> <message> <source>medium</source> - <translation type="unfinished"/> + <translation>μεσαία</translation> </message> <message> <source>low-medium</source> - <translation type="unfinished"/> + <translation>μεσαία-χαμηλή</translation> </message> <message> <source>low</source> - <translation type="unfinished"/> + <translation>χαμηλή</translation> </message> <message> <source>lower</source> - <translation type="unfinished"/> + <translation>χαμηλότερη</translation> </message> <message> <source>lowest</source> - <translation type="unfinished"/> + <translation>χαμηλότατη</translation> </message> <message> <source>(%1 locked)</source> - <translation type="unfinished"/> + <translation>(%1 κλειδωμένο)</translation> </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>κανένα</translation> </message> <message> <source>Dust</source> @@ -796,11 +796,12 @@ Address: %4 </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished"/> + <translation>ρέστα από %1 (%2) </translation> </message> <message> <source>(change)</source> - <translation type="unfinished"/> + <translation>(ρέστα) +</translation> </message> </context> <context> @@ -815,7 +816,7 @@ Address: %4 </message> <message> <source>The label associated with this address list entry</source> - <translation type="unfinished"/> + <translation>Η ετικέτα που συνδέεται με αυτήν την καταχώρηση στο βιβλίο διευθύνσεων</translation> </message> <message> <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> @@ -936,11 +937,11 @@ Address: %4 </message> <message> <source>Welcome to Bitcoin Core.</source> - <translation type="unfinished"/> + <translation>Καλώς ήρθατε στο Bitcoin Core.</translation> </message> <message> <source>As this is the first time the program is launched, you can choose where Bitcoin Core will store its data.</source> - <translation type="unfinished"/> + <translation>Καθώς αυτή είναι η πρώτη φορά που εκκινείται το πρόγραμμα, μπορείτε να διαλέξετε πού θα αποθηκεύει το Bitcoin Core τα δεδομένα του.</translation> </message> <message> <source>Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source> @@ -1030,7 +1031,7 @@ Address: %4 </message> <message> <source>MB</source> - <translation type="unfinished"/> + <translation>MB</translation> </message> <message> <source>Number of script &verification threads</source> @@ -1082,7 +1083,7 @@ Address: %4 </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>Έμπειρος</translation> </message> <message> <source>Enable coin &control features</source> @@ -1190,7 +1191,7 @@ Address: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>κανένα</translation> </message> <message> <source>Confirm options reset</source> @@ -1198,7 +1199,7 @@ Address: %4 </message> <message> <source>Client restart required to activate changes.</source> - <translation type="unfinished"/> + <translation>Χρειάζεται επανεκκίνηση του προγράμματος για να ενεργοποιηθούν οι αλλαγές.</translation> </message> <message> <source>Client will be shutdown, do you want to proceed?</source> @@ -1229,7 +1230,7 @@ Address: %4 </message> <message> <source>Available:</source> - <translation type="unfinished"/> + <translation>Διαθέσιμο:</translation> </message> <message> <source>Your current spendable balance</source> @@ -1370,11 +1371,11 @@ Address: %4 <name>QRImageWidget</name> <message> <source>&Save Image...</source> - <translation type="unfinished"/> + <translation>&Αποθήκευση εικόνας...</translation> </message> <message> <source>&Copy Image</source> - <translation type="unfinished"/> + <translation>&Αντιγραφή εικόνας</translation> </message> <message> <source>Save QR Code</source> @@ -1409,7 +1410,7 @@ Address: %4 </message> <message> <source>General</source> - <translation type="unfinished"/> + <translation>Γενικά</translation> </message> <message> <source>Using OpenSSL version</source> @@ -1425,7 +1426,7 @@ Address: %4 </message> <message> <source>Name</source> - <translation type="unfinished"/> + <translation>Όνομα</translation> </message> <message> <source>Number of connections</source> @@ -1457,11 +1458,11 @@ Address: %4 </message> <message> <source>&Network Traffic</source> - <translation type="unfinished"/> + <translation>&Κίνηση δικτύου</translation> </message> <message> <source>&Clear</source> - <translation type="unfinished"/> + <translation>&Εκκαθάριση</translation> </message> <message> <source>Totals</source> @@ -1536,7 +1537,7 @@ Address: %4 <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation type="unfinished"/> + <translation>&Ποσό:</translation> </message> <message> <source>&Label:</source> @@ -1544,7 +1545,7 @@ Address: %4 </message> <message> <source>&Message:</source> - <translation type="unfinished"/> + <translation>&Μήνυμα:</translation> </message> <message> <source>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</source> @@ -1584,7 +1585,7 @@ Address: %4 </message> <message> <source>&Request payment</source> - <translation type="unfinished"/> + <translation>&Αίτηση πληρωμής</translation> </message> <message> <source>Show the selected request (does the same as double clicking an entry)</source> @@ -1608,7 +1609,7 @@ Address: %4 </message> <message> <source>Copy message</source> - <translation type="unfinished"/> + <translation>Αντιγραφή μηνύματος</translation> </message> <message> <source>Copy amount</source> @@ -1631,7 +1632,7 @@ Address: %4 </message> <message> <source>&Save Image...</source> - <translation type="unfinished"/> + <translation>&Αποθήκευση εικόνας...</translation> </message> <message> <source>Request payment to %1</source> @@ -1698,7 +1699,7 @@ Address: %4 </message> <message> <source>(no amount)</source> - <translation type="unfinished"/> + <translation>(κανένα ποσό)</translation> </message> </context> <context> @@ -1717,7 +1718,7 @@ Address: %4 </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>επιλεγμένο αυτόματα</translation> </message> <message> <source>Insufficient funds!</source> @@ -1753,7 +1754,7 @@ Address: %4 </message> <message> <source>Change:</source> - <translation type="unfinished"/> + <translation>Ρέστα:</translation> </message> <message> <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> @@ -1801,7 +1802,7 @@ Address: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>Αντιγραφή ποσότητας</translation> </message> <message> <source>Copy amount</source> @@ -1817,11 +1818,11 @@ Address: %4 </message> <message> <source>Copy bytes</source> - <translation type="unfinished"/> + <translation>Αντιγραφή των byte</translation> </message> <message> <source>Copy priority</source> - <translation type="unfinished"/> + <translation>Αντιγραφή προτεραιότητας</translation> </message> <message> <source>Copy low output</source> @@ -1829,15 +1830,15 @@ Address: %4 </message> <message> <source>Copy change</source> - <translation type="unfinished"/> + <translation>Αντιγραφή των ρέστων</translation> </message> <message> <source>Total Amount %1 (= %2)</source> - <translation type="unfinished"/> + <translation>Ολικό Ποσό %1 (= %2)</translation> </message> <message> <source>or</source> - <translation type="unfinished"/> + <translation>ή</translation> </message> <message> <source>The recipient address is not valid, please recheck.</source> @@ -1940,7 +1941,7 @@ Address: %4 </message> <message> <source>Remove this entry</source> - <translation type="unfinished"/> + <translation>Αφαίρεση αυτής της καταχώρησης</translation> </message> <message> <source>Message:</source> @@ -1975,11 +1976,11 @@ Address: %4 <name>ShutdownWindow</name> <message> <source>Bitcoin Core is shutting down...</source> - <translation type="unfinished"/> + <translation>Το Bitcoin Core τερματίζεται...</translation> </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished"/> + <translation>Μην απενεργοποιήσετε τον υπολογιστή μέχρι να κλείσει αυτό το παράθυρο.</translation> </message> </context> <context> @@ -2133,7 +2134,7 @@ Address: %4 </message> <message> <source>The Bitcoin Core developers</source> - <translation type="unfinished"/> + <translation>Οι προγραμματιστές του Bitcoin Core</translation> </message> <message> <source>[testnet]</source> @@ -2341,11 +2342,11 @@ Address: %4 </message> <message> <source>Offline</source> - <translation type="unfinished"/> + <translation>Offline</translation> </message> <message> <source>Unconfirmed</source> - <translation type="unfinished"/> + <translation>Ανεπιβεβαίωτες</translation> </message> <message> <source>Confirming (%1 of %2 recommended confirmations)</source> @@ -2484,19 +2485,19 @@ Address: %4 </message> <message> <source>Export Transaction History</source> - <translation type="unfinished"/> + <translation>Εξαγωγή Ιστορικού Συναλλαγών</translation> </message> <message> <source>Exporting Failed</source> - <translation type="unfinished"/> + <translation>Η Εξαγωγή Απέτυχε</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> - <translation type="unfinished"/> + <translation>Yπήρξε σφάλμα κατά την προσπάθεια αποθήκευσης του ιστορικού συναλλαγών στο %1.</translation> </message> <message> <source>Exporting Successful</source> - <translation type="unfinished"/> + <translation>Επιτυχής εξαγωγή</translation> </message> <message> <source>The transaction history was successfully saved to %1.</source> @@ -2547,7 +2548,7 @@ Address: %4 <name>WalletFrame</name> <message> <source>No wallet has been loaded.</source> - <translation type="unfinished"/> + <translation>Δεν έχει φορτωθεί πορτοφόλι</translation> </message> </context> <context> @@ -2585,7 +2586,7 @@ Address: %4 </message> <message> <source>The wallet data was successfully saved to %1.</source> - <translation type="unfinished"/> + <translation>Τα δεδομένα πορτοφολιού αποθηκεύτηκαν με επιτυχία στο %1.</translation> </message> <message> <source>Backup Successful</source> @@ -2801,11 +2802,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>(default: 1)</source> - <translation type="unfinished"/> + <translation>(προεπιλογή: 1)</translation> </message> <message> <source>(default: wallet.dat)</source> - <translation type="unfinished"/> + <translation>(προεπιλογή: wallet.dat)</translation> </message> <message> <source><category> can be:</source> @@ -2841,7 +2842,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>Επιλογές σύνδεσης:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -3045,7 +3046,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Wallet options:</source> - <translation type="unfinished"/> + <translation>Επιλογές πορτοφολιού:</translation> </message> <message> <source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source> @@ -3229,7 +3230,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>on startup</source> - <translation type="unfinished"/> + <translation>κατά την εκκίνηση</translation> </message> <message> <source>version</source> diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts index 1a46c6ae6..2ad31e911 100644 --- a/src/qt/locale/bitcoin_sl_SI.ts +++ b/src/qt/locale/bitcoin_sl_SI.ts @@ -344,7 +344,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Modify configuration options for Bitcoin</source> - <translation type="unfinished"/> + <translation>Spremeni konfiguracijo nastavitev za Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> @@ -1144,7 +1144,7 @@ Naslov: %4 </message> <message> <source>User Interface &language:</source> - <translation type="unfinished"/> + <translation>Vmesnik uporabnika &jezik:</translation> </message> <message> <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source> @@ -1487,11 +1487,11 @@ Naslov: %4 </message> <message> <source>Welcome to the Bitcoin RPC console.</source> - <translation type="unfinished"/> + <translation>Dobrodošli na Bitcoin RPC konzoli.</translation> </message> <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> - <translation type="unfinished"/> + <translation>Uporabi puščice za gor in dol za navigacijo po zgodovini in <b>Ctrl-L</b> za izbris izpisa na ekranu.</translation> </message> <message> <source>Type <b>help</b> for an overview of available commands.</source> @@ -1847,7 +1847,7 @@ Naslov: %4 </message> <message> <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished"/> + <translation>Celotni znesek presega vaše stanje, ko je zaračunana 1% provizija.</translation> </message> <message> <source>Duplicate address found, can only send to each address once per send operation.</source> @@ -2626,7 +2626,7 @@ Naslov: %4 </message> <message> <source>Connect to a node to retrieve peer addresses, and disconnect</source> - <translation type="unfinished"/> + <translation>Povežite se z vozliščem za pridobitev naslovov uporabnikov in nato prekinite povezavo.</translation> </message> <message> <source>Specify your own public address</source> @@ -2638,7 +2638,7 @@ Naslov: %4 </message> <message> <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> - <translation type="unfinished"/> + <translation>Število sekund za težavo pri vzpostavitvi povezave med uporabniki (privzeto: 86400)</translation> </message> <message> <source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source> @@ -3268,11 +3268,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Unable to bind to %s on this computer (bind returned error %d, %s)</source> - <translation type="unfinished"/> + <translation>Nemogoče je povezati s/z %s na tem računalniku (povezava je vrnila napaka %d, %s)</translation> </message> <message> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> - <translation type="unfinished"/> + <translation>Omogoči DNS poizvedbe za -addnode, -seednode in -connect.</translation> </message> <message> <source>Loading addresses...</source> @@ -3296,27 +3296,27 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid -proxy address: '%s'</source> - <translation type="unfinished"/> + <translation>Neveljaven -proxy naslov: '%s'</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished"/> + <translation>Neznano omrežje določeno v -onlynet: '%s'.</translation> </message> <message> <source>Unknown -socks proxy version requested: %i</source> - <translation type="unfinished"/> + <translation>Neznano -socks zahtevan zastopnik različice: %i</translation> </message> <message> <source>Cannot resolve -bind address: '%s'</source> - <translation type="unfinished"/> + <translation>Nemogoče rešiti -bind naslova: '%s'</translation> </message> <message> <source>Cannot resolve -externalip address: '%s'</source> - <translation type="unfinished"/> + <translation>Nemogoče rešiti -externalip naslova: '%s'</translation> </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> - <translation type="unfinished"/> + <translation>Neveljavna količina za -paytxfee=<amount>: '%s'</translation> </message> <message> <source>Invalid amount</source> @@ -3344,7 +3344,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Cannot write default address</source> - <translation type="unfinished"/> + <translation>Ni mogoče zapisati privzetega naslova</translation> </message> <message> <source>Rescanning...</source> @@ -3356,7 +3356,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>To use the %s option</source> - <translation type="unfinished"/> + <translation>Za uporabo %s opcije</translation> </message> <message> <source>Error</source> @@ -3366,7 +3366,9 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <source>You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions.</source> - <translation type="unfinished"/> + <translation>Potrebno je nastaviti rpcpassword=<password> v nastavitveni datoteki: +%s +Če datoteka ne obstaja jo ustvarite z dovoljenjem, da jo lahko bere samo uporabnik.</translation> </message> </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index 96c49b12d..54e15a75e 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -35,7 +35,7 @@ This product includes software developed by the OpenSSL Project for use in the O <name>AddressBookPage</name> <message> <source>Double-click to edit address or label</source> - <translation>ดับเบิลคลิก เพื่อแก้ไขที่อยู่ หรือชื่อ</translation> + <translation>ดับเบิ้ลคลิก เพื่อแก้ไขที่อยู่ หรือชื่อ</translation> </message> <message> <source>Create a new address</source> @@ -75,7 +75,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Delete</source> - <translation>ลบ</translation> + <translation>&ลบ</translation> </message> <message> <source>Choose the address to send coins to</source> @@ -119,7 +119,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Comma separated file (*.csv)</source> - <translation type="unfinished"/> + <translation>คั่นไฟล์ด้วยเครื่องหมายจุลภาค (*.csv)</translation> </message> <message> <source>Exporting Failed</source> @@ -165,7 +165,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>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>.</source> - <translation type="unfinished"/> + <translation>ใส่รหัสผ่านใหม่ให้กับกระเป๋าเงิน. <br/> กรุณาใช้รหัสผ่านของ <b> 10 หรือแบบสุ่มมากกว่าตัวอักษร </ b> หรือ <b> แปดหรือมากกว่าคำ </ b></translation> </message> <message> <source>Encrypt wallet</source> @@ -173,7 +173,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished"/> + <translation>การดำเนินการนี้ต้องมีรหัสผ่านกระเป๋าเงินของคุณเพื่อปลดล็อคกระเป๋าเงิน</translation> </message> <message> <source>Unlock wallet</source> @@ -181,7 +181,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>This operation needs your wallet passphrase to decrypt the wallet.</source> - <translation type="unfinished"/> + <translation>การดำเนินการนี้ต้องมีรหัสผ่านกระเป๋าเงินของคุณในการถอดรหัสกระเป๋าเงิน</translation> </message> <message> <source>Decrypt wallet</source> @@ -229,7 +229,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished"/> + <translation>กระเป๋าเงินเข้ารหัสล้มเหลวเนื่องจากข้อผิดพลาดภายใน กระเป๋าเงินของคุณไม่ได้เข้ารหัส</translation> </message> <message> <source>The supplied passphrases do not match.</source> @@ -237,15 +237,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Wallet unlock failed</source> - <translation type="unfinished"/> + <translation>ปลดล็อคกระเป๋าเงินล้มเหลว</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished"/> + <translation>ป้อนรหัสผ่านสำหรับการถอดรหัสกระเป๋าเงินไม่ถูกต้อง</translation> </message> <message> <source>Wallet decryption failed</source> - <translation type="unfinished"/> + <translation>ถอดรหัสกระเป๋าเงินล้มเหลว</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> @@ -260,11 +260,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Synchronizing with network...</source> - <translation type="unfinished"/> + <translation>กำลังทำข้อมูลให้ตรงกันกับเครือข่าย ...</translation> </message> <message> <source>&Overview</source> - <translation type="unfinished"/> + <translation>&ภาพรวม</translation> </message> <message> <source>Node</source> @@ -272,15 +272,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Show general overview of wallet</source> - <translation type="unfinished"/> + <translation>แสดงภาพรวมทั่วไปของกระเป๋าเงิน</translation> </message> <message> <source>&Transactions</source> - <translation type="unfinished"/> + <translation>&การทำรายการ</translation> </message> <message> <source>Browse transaction history</source> - <translation type="unfinished"/> + <translation>เรียกดูประวัติการทำธุรกรรม</translation> </message> <message> <source>E&xit</source> @@ -288,11 +288,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Quit application</source> - <translation type="unfinished"/> + <translation>ออกจากโปรแกรม</translation> </message> <message> <source>Show information about Bitcoin</source> - <translation type="unfinished"/> + <translation>แสดงข้อมูลเกี่ยวกับ Bitcoin</translation> </message> <message> <source>About &Qt</source> @@ -304,7 +304,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Options...</source> - <translation type="unfinished"/> + <translation>&ตัวเลือก...</translation> </message> <message> <source>&Encrypt Wallet...</source> @@ -352,7 +352,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished"/> + <translation>เปลี่ยนรหัสผ่านที่ใช้สำหรับการเข้ารหัสกระเป๋าเงิน</translation> </message> <message> <source>&Debug window</source> @@ -404,23 +404,23 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&File</source> - <translation type="unfinished"/> + <translation>&ไฟล์</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished"/> + <translation>&การตั้งค่า</translation> </message> <message> <source>&Help</source> - <translation type="unfinished"/> + <translation>&ช่วยเหลือ</translation> </message> <message> <source>Tabs toolbar</source> - <translation type="unfinished"/> + <translation>แถบเครื่องมือ</translation> </message> <message> <source>[testnet]</source> - <translation type="unfinished"/> + <translation>[testnet]</translation> </message> <message> <source>Bitcoin Core</source> @@ -460,7 +460,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> - <translation type="unfinished"><numerusform></numerusform></translation> + <translation><numerusform>%n ที่ใช้งานการเชื่อมต่อกับเครือข่าย Bitcoin</numerusform></translation> </message> <message> <source>No block source available...</source> @@ -520,19 +520,19 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Up to date</source> - <translation type="unfinished"/> + <translation>ทันสมัย</translation> </message> <message> <source>Catching up...</source> - <translation type="unfinished"/> + <translation>จับได้...</translation> </message> <message> <source>Sent transaction</source> - <translation type="unfinished"/> + <translation>รายการที่ส่ง</translation> </message> <message> <source>Incoming transaction</source> - <translation type="unfinished"/> + <translation>การทำรายการขาเข้า</translation> </message> <message> <source>Date: %1 @@ -544,11 +544,11 @@ Address: %4 </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished"/> + <translation>ระเป๋าเงินถูก <b>เข้ารหัส</b> และในขณะนี้ <b>ปลดล็อคแล้ว</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished"/> + <translation>กระเป๋าเงินถูก <b>เข้ารหัส</b> และในปัจจุบัน <b>ล็อค </b></translation> </message> <message> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> @@ -797,11 +797,11 @@ Address: %4 <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation type="unfinished"/> + <translation>แก้ไขที่อยู่</translation> </message> <message> <source>&Label</source> - <translation type="unfinished"/> + <translation>&ชื่อ</translation> </message> <message> <source>The label associated with this address list entry</source> @@ -813,27 +813,27 @@ Address: %4 </message> <message> <source>&Address</source> - <translation type="unfinished"/> + <translation>&ที่อยู่</translation> </message> <message> <source>New receiving address</source> - <translation type="unfinished"/> + <translation>ที่อยู่ผู้รับใหม่</translation> </message> <message> <source>New sending address</source> - <translation type="unfinished"/> + <translation>ที่อยู่ผู้ส่งใหม่</translation> </message> <message> <source>Edit receiving address</source> - <translation type="unfinished"/> + <translation>แก้ไขที่อยู่ผู้รับ</translation> </message> <message> <source>Edit sending address</source> - <translation type="unfinished"/> + <translation>แก้ไขที่อยู่ผู้ส่ง</translation> </message> <message> <source>The entered address "%1" is already in the address book.</source> - <translation type="unfinished"/> + <translation>ป้อนที่อยู่ "%1" ที่มีอยู่แล้วในสมุดที่อยู่</translation> </message> <message> <source>The entered address "%1" is not a valid Bitcoin address.</source> @@ -841,11 +841,11 @@ Address: %4 </message> <message> <source>Could not unlock wallet.</source> - <translation type="unfinished"/> + <translation>ไม่สามารถปลดล็อคกระเป๋าเงิน</translation> </message> <message> <source>New key generation failed.</source> - <translation type="unfinished"/> + <translation>สร้างกุญแจใหม่ล้มเหลว</translation> </message> </context> <context> @@ -992,7 +992,7 @@ Address: %4 <name>OptionsDialog</name> <message> <source>Options</source> - <translation type="unfinished"/> + <translation>ตัวเลือก</translation> </message> <message> <source>&Main</source> @@ -1207,7 +1207,7 @@ Address: %4 <name>OverviewPage</name> <message> <source>Form</source> - <translation type="unfinished"/> + <translation>รูป</translation> </message> <message> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> @@ -1251,7 +1251,7 @@ Address: %4 </message> <message> <source><b>Recent transactions</b></source> - <translation type="unfinished"/> + <translation><b>รายการทำธุรกรรมล่าสุด</b></translation> </message> <message> <source>out of sync</source> @@ -1695,7 +1695,7 @@ Address: %4 <name>SendCoinsDialog</name> <message> <source>Send Coins</source> - <translation type="unfinished"/> + <translation>ส่งเหรียญ</translation> </message> <message> <source>Coin Control Features</source> @@ -2127,7 +2127,7 @@ Address: %4 </message> <message> <source>[testnet]</source> - <translation type="unfinished"/> + <translation>[testnet]</translation> </message> </context> <context> @@ -2494,7 +2494,7 @@ Address: %4 </message> <message> <source>Comma separated file (*.csv)</source> - <translation type="unfinished"/> + <translation>คั่นไฟล์ด้วยเครื่องหมายจุลภาค (*.csv)</translation> </message> <message> <source>Confirmed</source> @@ -2544,7 +2544,7 @@ Address: %4 <name>WalletModel</name> <message> <source>Send Coins</source> - <translation type="unfinished"/> + <translation>ส่งเหรียญ</translation> </message> </context> <context> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 96464d2cc..1cbf5f881 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -14,7 +14,7 @@ #include "monitoreddatamapper.h" #include "optionsmodel.h" -#include "main.h" // for CTransaction::nMinTxFee and MAX_SCRIPTCHECK_THREADS +#include "main.h" // for CTransaction::minTxFee and MAX_SCRIPTCHECK_THREADS #include "netbase.h" #include "txdb.h" // for -dbcache defaults @@ -101,7 +101,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) : #endif ui->unit->setModel(new BitcoinUnits(this)); - ui->transactionFee->setSingleStep(CTransaction::nMinTxFee); + ui->transactionFee->setSingleStep(CTransaction::minTxFee.GetFeePerK()); /* Widget-to-option mapper */ mapper = new MonitoredDataMapper(this); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 051098315..f3a5f37bb 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -94,7 +94,7 @@ void OptionsModel::Init() #ifdef ENABLE_WALLET if (!settings.contains("nTransactionFee")) settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE); - nTransactionFee = settings.value("nTransactionFee").toLongLong(); // if -paytxfee is set, this will be overridden later in init.cpp + payTxFee = CFeeRate(settings.value("nTransactionFee").toLongLong()); // if -paytxfee is set, this will be overridden later in init.cpp if (mapArgs.count("-paytxfee")) addOverriddenOption("-paytxfee"); @@ -187,15 +187,16 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const return settings.value("nSocksVersion", 5); #ifdef ENABLE_WALLET - case Fee: - // Attention: Init() is called before nTransactionFee is set in AppInit2()! + case Fee: { + // Attention: Init() is called before payTxFee is set in AppInit2()! // To ensure we can change the fee on-the-fly update our QSetting when // opening OptionsDialog, which queries Fee via the mapper. - if (nTransactionFee != settings.value("nTransactionFee").toLongLong()) - settings.setValue("nTransactionFee", (qint64)nTransactionFee); - // Todo: Consider to revert back to use just nTransactionFee here, if we don't want + if (!(payTxFee == CFeeRate(settings.value("nTransactionFee").toLongLong(), 1000))) + settings.setValue("nTransactionFee", (qint64)payTxFee.GetFeePerK()); + // Todo: Consider to revert back to use just payTxFee here, if we don't want // -paytxfee to update our QSettings! return settings.value("nTransactionFee"); + } case SpendZeroConfChange: return settings.value("bSpendZeroConfChange"); #endif @@ -284,12 +285,14 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in } break; #ifdef ENABLE_WALLET - case Fee: // core option - can be changed on-the-fly + case Fee: { // core option - can be changed on-the-fly // Todo: Add is valid check and warn via message, if not - nTransactionFee = value.toLongLong(); - settings.setValue("nTransactionFee", (qint64)nTransactionFee); + qint64 nTransactionFee = value.toLongLong(); + payTxFee = CFeeRate(nTransactionFee, 1000); + settings.setValue("nTransactionFee", nTransactionFee); emit transactionFeeChanged(nTransactionFee); break; + } case SpendZeroConfChange: if (settings.value("bSpendZeroConfChange") != value) { settings.setValue("bSpendZeroConfChange", value); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 4c4558568..9241f9dc3 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -490,6 +490,17 @@ bool PaymentServer::readPaymentRequest(const QString& filename, PaymentRequestPl return request.parse(data); } +std::string PaymentServer::mapNetworkIdToName(CChainParams::Network networkId) +{ + if (networkId == CChainParams::MAIN) + return "main"; + if (networkId == CChainParams::TESTNET) + return "test"; + if (networkId == CChainParams::REGTEST) + return "regtest"; + return ""; +} + bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient) { if (!optionsModel) @@ -499,8 +510,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins const payments::PaymentDetails& details = request.getDetails(); // Payment request network matches client network? - if ((details.network() == "main" && TestNet()) || - (details.network() == "test" && !TestNet())) + if (details.network() != mapNetworkIdToName(Params().NetworkID())) { emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), CClientUIInterface::MSG_ERROR); @@ -551,7 +561,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins // Extract and check amounts CTxOut txOut(sendingTo.second, sendingTo.first); - if (txOut.IsDust(CTransaction::nMinRelayTxFee)) { + if (txOut.IsDust(CTransaction::minRelayTxFee)) { emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).") .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)), CClientUIInterface::MSG_ERROR); diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index d84d09c57..d6949a47c 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -118,6 +118,7 @@ protected: private: static bool readPaymentRequest(const QString& filename, PaymentRequestPlus& request); + std::string mapNetworkIdToName(CChainParams::Network networkId); bool processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient); void fetchRequest(const QUrl& url); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp new file mode 100644 index 000000000..981d063c4 --- /dev/null +++ b/src/qt/peertablemodel.cpp @@ -0,0 +1,236 @@ +// Copyright (c) 2011-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. + +#include "peertablemodel.h" + +#include "clientmodel.h" + +#include "net.h" +#include "sync.h" + +#include <QDebug> +#include <QList> +#include <QTimer> + +bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const +{ + const CNodeStats *pLeft = &(left.nodestats); + const CNodeStats *pRight = &(right.nodestats); + + if (order == Qt::DescendingOrder) + std::swap(pLeft, pRight); + + switch(column) + { + case PeerTableModel::Address: + return pLeft->addrName.compare(pRight->addrName) < 0; + case PeerTableModel::Subversion: + return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; + case PeerTableModel::Height: + return pLeft->nStartingHeight < pRight->nStartingHeight; + } + + return false; +} + +// private implementation +class PeerTablePriv +{ +public: + /** Local cache of peer information */ + QList<CNodeCombinedStats> cachedNodeStats; + /** Column to sort nodes by */ + int sortColumn; + /** Order (ascending or descending) to sort nodes by */ + Qt::SortOrder sortOrder; + /** Index of rows by node ID */ + std::map<NodeId, int> mapNodeRows; + + /** Pull a full list of peers from vNodes into our cache */ + void refreshPeers() { + { + TRY_LOCK(cs_vNodes, lockNodes); + if (!lockNodes) + { + // skip the refresh if we can't immediately get the lock + return; + } + cachedNodeStats.clear(); +#if QT_VERSION >= 0x040700 + cachedNodeStats.reserve(vNodes.size()); +#endif + BOOST_FOREACH(CNode* pnode, vNodes) + { + CNodeCombinedStats stats; + stats.statestats.nMisbehavior = -1; + pnode->copyStats(stats.nodestats); + cachedNodeStats.append(stats); + } + } + + // if we can, retrieve the CNodeStateStats for each node. + { + TRY_LOCK(cs_main, lockMain); + if (lockMain) + { + BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats) + { + GetNodeStateStats(stats.nodestats.nodeid, stats.statestats); + } + } + } + + if (sortColumn >= 0) + // sort cacheNodeStats (use stable sort to prevent rows jumping around unneceesarily) + qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); + + // build index map + mapNodeRows.clear(); + int row = 0; + BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats) + { + mapNodeRows.insert(std::pair<NodeId, int>(stats.nodestats.nodeid, row++)); + } + } + + int size() + { + return cachedNodeStats.size(); + } + + CNodeCombinedStats *index(int idx) + { + if(idx >= 0 && idx < cachedNodeStats.size()) { + return &cachedNodeStats[idx]; + } + else + { + return 0; + } + } +}; + +PeerTableModel::PeerTableModel(ClientModel *parent) : + QAbstractTableModel(parent),clientModel(parent),timer(0) +{ + columns << tr("Address") << tr("User Agent") << tr("Start Height"); + priv = new PeerTablePriv(); + // default to unsorted + priv->sortColumn = -1; + + // set up timer for auto refresh + timer = new QTimer(); + connect(timer, SIGNAL(timeout()), SLOT(refresh())); + + // load initial data + refresh(); +} + +void PeerTableModel::startAutoRefresh(int msecs) +{ + timer->setInterval(1000); + timer->start(); +} + +void PeerTableModel::stopAutoRefresh() +{ + timer->stop(); +} + +int PeerTableModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return priv->size(); +} + +int PeerTableModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 3; +} + +QVariant PeerTableModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer()); + + if(role == Qt::DisplayRole) + { + switch(index.column()) + { + case Address: + return QVariant(rec->nodestats.addrName.c_str()); + case Subversion: + return QVariant(rec->nodestats.cleanSubVer.c_str()); + case Height: + return rec->nodestats.nStartingHeight; + } + } + return QVariant(); +} + +QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Horizontal) + { + if(role == Qt::DisplayRole && section < columns.size()) + { + return columns[section]; + } + } + return QVariant(); +} + +Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const +{ + if(!index.isValid()) + return 0; + + Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + return retval; +} + +QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent); + CNodeCombinedStats *data = priv->index(row); + + if (data) + { + return createIndex(row, column, data); + } + else + { + return QModelIndex(); + } +} + +const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx) { + return priv->index(idx); +} + +void PeerTableModel::refresh() +{ + emit layoutAboutToBeChanged(); + priv->refreshPeers(); + emit layoutChanged(); +} + +int PeerTableModel::getRowByNodeId(NodeId nodeid) +{ + std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid); + if (it == priv->mapNodeRows.end()) + return -1; + + return it->second; +} + +void PeerTableModel::sort(int column, Qt::SortOrder order) +{ + priv->sortColumn = column; + priv->sortOrder = order; + refresh(); +} diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h new file mode 100644 index 000000000..385bf0e0c --- /dev/null +++ b/src/qt/peertablemodel.h @@ -0,0 +1,80 @@ +// Copyright (c) 2011-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 PEERTABLEMODEL_H +#define PEERTABLEMODEL_H + +#include "main.h" +#include "net.h" + +#include <QAbstractTableModel> +#include <QStringList> + +class ClientModel; +class PeerTablePriv; + +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + +struct CNodeCombinedStats { + CNodeStats nodestats; + CNodeStateStats statestats; +}; + +class NodeLessThan +{ +public: + NodeLessThan(int nColumn, Qt::SortOrder fOrder) : + column(nColumn), order(fOrder) {} + bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const; + +private: + int column; + Qt::SortOrder order; +}; + +/** + Qt model providing information about connected peers, similar to the + "getpeerinfo" RPC call. Used by the rpc console UI. + */ +class PeerTableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit PeerTableModel(ClientModel *parent = 0); + const CNodeCombinedStats *getNodeStats(int idx); + int getRowByNodeId(NodeId nodeid); + void startAutoRefresh(int msecs); + void stopAutoRefresh(); + + enum ColumnIndex { + Address = 0, + Subversion = 1, + Height = 2 + }; + + /** @name Methods overridden from QAbstractTableModel + @{*/ + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + void sort(int column, Qt::SortOrder order); + /*@}*/ + +public slots: + void refresh(); + +private: + ClientModel *clientModel; + QStringList columns; + PeerTablePriv *priv; + QTimer *timer; +}; + +#endif // PEERTABLEMODEL_H diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 062638f2b..d8dad15c0 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -13,10 +13,10 @@ #include <QClipboard> #include <QDrag> +#include <QMenu> #include <QMimeData> #include <QMouseEvent> #include <QPixmap> -#include <QMenu> #if QT_VERSION < 0x050000 #include <QUrl> #endif diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 5614ac635..9b78e495c 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -11,10 +11,12 @@ #include <QImage> #include <QLabel> +class OptionsModel; + namespace Ui { class ReceiveRequestDialog; } -class OptionsModel; + QT_BEGIN_NAMESPACE class QMenu; QT_END_NAMESPACE diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 0a46a722e..199050cc5 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -7,12 +7,19 @@ #include "clientmodel.h" #include "guiutil.h" +#include "peertablemodel.h" +#include "main.h" #include "rpcserver.h" #include "rpcclient.h" +#include "util.h" #include "json/json_spirit_value.h" +#ifdef ENABLE_WALLET +#include <db_cxx.h> +#endif #include <openssl/crypto.h> + #include <QKeyEvent> #include <QScrollBar> #include <QThread> @@ -195,6 +202,10 @@ RPCConsole::RPCConsole(QWidget *parent) : clientModel(0), historyPtr(0) { + detailNodeStats = CNodeCombinedStats(); + detailNodeStats.nodestats.nodeid = -1; + detailNodeStats.statestats.nMisbehavior = -1; + ui->setupUi(this); GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this); @@ -209,11 +220,18 @@ RPCConsole::RPCConsole(QWidget *parent) : connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); - // set OpenSSL version label + // set library version labels ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION)); +#ifdef ENABLE_WALLET + ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0)); +#else + ui->label_berkeleyDBVersion->hide(); + ui->berkeleyDBVersion->hide(); +#endif startExecutor(); setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS); + ui->detailWidget->hide(); clear(); } @@ -277,6 +295,21 @@ void RPCConsole::setClientModel(ClientModel *model) updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent()); connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64))); + // set up peer table + ui->peerWidget->setModel(model->getPeerTableModel()); + ui->peerWidget->verticalHeader()->hide(); + ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection); + ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH); + columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(ui->peerWidget, MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH); + + // connect the peerWidget's selection model to our peerSelected() handler + QItemSelectionModel *peerSelectModel = ui->peerWidget->selectionModel(); + connect(peerSelectModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &))); + connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged())); + // Provide initial values ui->clientVersion->setText(model->formatFullVersion()); ui->clientName->setText(model->clientName()); @@ -382,8 +415,8 @@ void RPCConsole::on_lineEdit_returnPressed() { message(CMD_REQUEST, cmd); emit cmdRequest(cmd); - // Truncate history from current position - history.erase(history.begin() + historyPtr, history.end()); + // Remove command, if already in history + history.removeOne(cmd); // Append command to history history.append(cmd); // Enforce maximum history size @@ -474,17 +507,7 @@ QString RPCConsole::FormatBytes(quint64 bytes) void RPCConsole::setTrafficGraphRange(int mins) { ui->trafficGraph->setGraphRangeMins(mins); - if(mins < 60) { - ui->lblGraphRange->setText(QString(tr("%1 m")).arg(mins)); - } else { - int hours = mins / 60; - int minsLeft = mins % 60; - if(minsLeft == 0) { - ui->lblGraphRange->setText(QString(tr("%1 h")).arg(hours)); - } else { - ui->lblGraphRange->setText(QString(tr("%1 h %2 m")).arg(hours).arg(minsLeft)); - } - } + ui->lblGraphRange->setText(GUIUtil::formatDurationStr(mins * 60)); } void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut) @@ -492,3 +515,161 @@ void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut) ui->lblBytesIn->setText(FormatBytes(totalBytesIn)); ui->lblBytesOut->setText(FormatBytes(totalBytesOut)); } + +void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected) +{ + Q_UNUSED(deselected); + + if (selected.indexes().isEmpty()) + return; + + // mark the cached banscore as unknown + detailNodeStats.statestats.nMisbehavior = -1; + + const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row()); + + if (stats) + { + detailNodeStats.nodestats.nodeid = stats->nodestats.nodeid; + updateNodeDetail(stats); + ui->detailWidget->show(); + ui->detailWidget->setDisabled(false); + } +} + +void RPCConsole::peerLayoutChanged() +{ + const CNodeCombinedStats *stats = NULL; + bool fUnselect = false, fReselect = false, fDisconnected = false; + + if (detailNodeStats.nodestats.nodeid == -1) + // no node selected yet + return; + + // find the currently selected row + int selectedRow; + QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes(); + if (selectedModelIndex.isEmpty()) + selectedRow = -1; + else + selectedRow = selectedModelIndex.first().row(); + + // check if our detail node has a row in the table (it may not necessarily + // be at selectedRow since its position can change after a layout change) + int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(detailNodeStats.nodestats.nodeid); + + if (detailNodeRow < 0) + { + // detail node dissapeared from table (node disconnected) + fUnselect = true; + fDisconnected = true; + detailNodeStats.nodestats.nodeid = 0; + } + else + { + if (detailNodeRow != selectedRow) + { + // detail node moved position + fUnselect = true; + fReselect = true; + } + + // get fresh stats on the detail node. + stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); + } + + if (fUnselect && selectedRow >= 0) + { + ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()), + QItemSelectionModel::Deselect); + } + + if (fReselect) + { + ui->peerWidget->selectRow(detailNodeRow); + } + + if (stats) + updateNodeDetail(stats); + + if (fDisconnected) + { + ui->peerHeading->setText(QString(tr("Peer Disconnected"))); + ui->detailWidget->setDisabled(true); + QDateTime dt = QDateTime::fromTime_t(detailNodeStats.nodestats.nLastSend); + if (detailNodeStats.nodestats.nLastSend) + ui->peerLastSend->setText(dt.toString("yyyy-MM-dd hh:mm:ss")); + dt.setTime_t(detailNodeStats.nodestats.nLastRecv); + if (detailNodeStats.nodestats.nLastRecv) + ui->peerLastRecv->setText(dt.toString("yyyy-MM-dd hh:mm:ss")); + dt.setTime_t(detailNodeStats.nodestats.nTimeConnected); + ui->peerConnTime->setText(dt.toString("yyyy-MM-dd hh:mm:ss")); + } +} + +void RPCConsole::updateNodeDetail(const CNodeCombinedStats *combinedStats) +{ + CNodeStats stats = combinedStats->nodestats; + + // keep a copy of timestamps, used to display dates upon disconnect + detailNodeStats.nodestats.nLastSend = stats.nLastSend; + detailNodeStats.nodestats.nLastRecv = stats.nLastRecv; + detailNodeStats.nodestats.nTimeConnected = stats.nTimeConnected; + + // update the detail ui with latest node information + ui->peerHeading->setText(QString("<b>%1</b>").arg(tr("Node Detail"))); + ui->peerAddr->setText(QString(stats.addrName.c_str())); + ui->peerServices->setText(GUIUtil::formatServicesStr(stats.nServices)); + ui->peerLastSend->setText(stats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats.nLastSend) : tr("never")); + ui->peerLastRecv->setText(stats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats.nLastRecv) : tr("never")); + ui->peerBytesSent->setText(FormatBytes(stats.nSendBytes)); + ui->peerBytesRecv->setText(FormatBytes(stats.nRecvBytes)); + ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats.nTimeConnected)); + ui->peerPingTime->setText(stats.dPingTime == 0 ? tr("N/A") : QString(tr("%1 secs")).arg(QString::number(stats.dPingTime, 'f', 3))); + ui->peerVersion->setText(QString("%1").arg(stats.nVersion)); + ui->peerSubversion->setText(QString(stats.cleanSubVer.c_str())); + ui->peerDirection->setText(stats.fInbound ? tr("Inbound") : tr("Outbound")); + ui->peerHeight->setText(QString("%1").arg(stats.nStartingHeight)); + ui->peerSyncNode->setText(stats.fSyncNode ? tr("Yes") : tr("No")); + + // if we can, display the peer's ban score + CNodeStateStats statestats = combinedStats->statestats; + if (statestats.nMisbehavior >= 0) + { + // we have a new nMisbehavor value - update the cache + detailNodeStats.statestats.nMisbehavior = statestats.nMisbehavior; + } + + // pull the ban score from cache. -1 means it hasn't been retrieved yet (lock busy). + if (detailNodeStats.statestats.nMisbehavior >= 0) + ui->peerBanScore->setText(QString("%1").arg(detailNodeStats.statestats.nMisbehavior)); + else + ui->peerBanScore->setText(tr("Fetching...")); +} + +// We override the virtual resizeEvent of the QWidget to adjust tables column +// sizes as the tables width is proportional to the dialogs width. +void RPCConsole::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + columnResizingFixer->stretchColumnWidth(PeerTableModel::Address); +} + +void RPCConsole::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + + // peerWidget needs a resize in case the dialog has non-default geometry + columnResizingFixer->stretchColumnWidth(PeerTableModel::Address); + + // start PeerTableModel auto refresh + clientModel->getPeerTableModel()->startAutoRefresh(1000); +} + +void RPCConsole::hideEvent(QHideEvent *event) +{ + QWidget::hideEvent(event); + + // stop PeerTableModel auto refresh + clientModel->getPeerTableModel()->stopAutoRefresh(); +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 091a6d294..3fee34d00 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -5,9 +5,19 @@ #ifndef RPCCONSOLE_H #define RPCCONSOLE_H +#include "guiutil.h" +#include "peertablemodel.h" + +#include "net.h" + #include <QDialog> class ClientModel; +class CNodeCombinedStats; + +QT_BEGIN_NAMESPACE +class QItemSelection; +QT_END_NAMESPACE namespace Ui { class RPCConsole; @@ -35,6 +45,19 @@ public: protected: virtual bool eventFilter(QObject* obj, QEvent *event); +private: + /** show detailed information on ui about selected node */ + void updateNodeDetail(const CNodeCombinedStats *combinedStats); + + enum ColumnWidths + { + ADDRESS_COLUMN_WIDTH = 250, + MINIMUM_COLUMN_WIDTH = 120 + }; + + /** track the node that we are currently viewing detail on in the peers tab */ + CNodeCombinedStats detailNodeStats; + private slots: void on_lineEdit_returnPressed(); void on_tabWidget_currentChanged(int index); @@ -44,6 +67,9 @@ private slots: void on_sldGraphRange_valueChanged(int value); /** update traffic statistics */ void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut); + void resizeEvent(QResizeEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); public slots: void clear(); @@ -57,6 +83,10 @@ public slots: void browseHistory(int offset); /** Scroll console view to end */ void scrollToEnd(); + /** Handle selection of peer in peers list */ + void peerSelected(const QItemSelection &selected, const QItemSelection &deselected); + /** Handle updated peer information */ + void peerLayoutChanged(); signals: // For RPC command executor @@ -70,6 +100,7 @@ private: Ui::RPCConsole *ui; ClientModel *clientModel; QStringList history; + GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer; int historyPtr; void startExecutor(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 23b8ef83e..b7d74d703 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -53,7 +53,7 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : 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 *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount())); @@ -478,7 +478,7 @@ void SendCoinsDialog::coinControlClipboardPriority() GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); } -// Coin Control: copy label "Low output" to clipboard +// Coin Control: copy label "Dust" to clipboard void SendCoinsDialog::coinControlClipboardLowOutput() { GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text()); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 7c79b0efd..1162e2d87 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -129,6 +129,7 @@ void SplashScreen::subscribeToCoreSignals() { // Connect signals to client uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1)); + uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); #ifdef ENABLE_WALLET uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1)); #endif @@ -138,6 +139,7 @@ void SplashScreen::unsubscribeFromCoreSignals() { // Disconnect signals from client uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); + uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); #ifdef ENABLE_WALLET if(pwalletMain) pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); diff --git a/src/qt/test/Makefile b/src/qt/test/Makefile new file mode 100644 index 000000000..a02f86b62 --- /dev/null +++ b/src/qt/test/Makefile @@ -0,0 +1,6 @@ +all: + $(MAKE) -C ../../ test_bitcoin_qt +clean: + $(MAKE) -C ../../ test_bitcoin_qt_clean +check: + $(MAKE) -C ../../ test_bitcoin_qt_check diff --git a/src/qt/test/Makefile.am b/src/qt/test/Makefile.am deleted file mode 100644 index 2461b5ff4..000000000 --- a/src/qt/test/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -include $(top_srcdir)/src/Makefile.include - -AM_CPPFLAGS += -I$(top_srcdir)/src \ - -I$(top_srcdir)/src/qt \ - -I$(top_builddir)/src/qt \ - $(PROTOBUF_CFLAGS) \ - $(QR_CFLAGS) -bin_PROGRAMS = test_bitcoin-qt -TESTS = test_bitcoin-qt - -TEST_QT_MOC_CPP = moc_uritests.cpp - -if ENABLE_WALLET -TEST_QT_MOC_CPP += moc_paymentservertests.cpp -endif - -TEST_QT_H = \ - uritests.h \ - paymentrequestdata.h \ - paymentservertests.h - -BUILT_SOURCES = $(TEST_QT_MOC_CPP) - -test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) $(QT_TEST_INCLUDES) - -test_bitcoin_qt_SOURCES = \ - test_main.cpp \ - uritests.cpp \ - $(TEST_QT_H) -if ENABLE_WALLET -test_bitcoin_qt_SOURCES += \ - paymentservertests.cpp -endif - -nodist_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) - -test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) -if ENABLE_WALLET -test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) -endif -test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \ - $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ - $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) -test_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS) - -CLEANFILES = $(BUILT_SOURCES) *.gcda *.gcno diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index f5a1328a7..4bd429321 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -9,6 +9,7 @@ #include <QString> class TransactionRecord; + class CWallet; class CWalletTx; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 37d82ec06..87ff3db58 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -231,12 +231,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return AmountExceedsBalance; } - if((total + nTransactionFee) > nBalance) - { - transaction.setTransactionFee(nTransactionFee); - return SendCoinsReturn(AmountWithFeeExceedsBalance); - } - { LOCK2(cs_main, wallet->cs_wallet); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index a303b5d3e..ff5057b52 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -427,7 +427,7 @@ Value verifychain(const Array& params, bool fHelp) if (params.size() > 1) nCheckDepth = params[1].get_int(); - return VerifyDB(nCheckLevel, nCheckDepth); + return CVerifyDB().VerifyDB(nCheckLevel, nCheckDepth); } Value getblockchaininfo(const Array& params, bool fHelp) diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 4f3c39ce9..b89a95ad1 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -176,6 +176,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "verifychain" && n > 1) ConvertTo<int64_t>(params[1]); if (strMethod == "keypoolrefill" && n > 0) ConvertTo<int64_t>(params[0]); if (strMethod == "getrawmempool" && n > 0) ConvertTo<bool>(params[0]); + if (strMethod == "estimatefee" && n > 0) ConvertTo<boost::int64_t>(params[0]); + if (strMethod == "estimatepriority" && n > 0) ConvertTo<boost::int64_t>(params[0]); return params; } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 23876c603..837f5336c 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -15,6 +15,7 @@ #endif #include <stdint.h> +#include <boost/assign/list_of.hpp> #include "json/json_spirit_utils.h" #include "json/json_spirit_value.h" @@ -174,7 +175,7 @@ Value setgenerate(const Array& params, bool fHelp) } // -regtest mode: don't return until nGenProcLimit blocks are generated - if (fGenerate && Params().NetworkID() == CChainParams::REGTEST) + if (fGenerate && Params().MineBlocksOnDemand()) { int nHeightStart = 0; int nHeightEnd = 0; @@ -265,7 +266,7 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", TestNet())); + obj.push_back(Pair("testnet", Params().RPCisTestNet())); #ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); @@ -626,3 +627,63 @@ Value submitblock(const Array& params, bool fHelp) return Value::null; } + +Value estimatefee(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatefee nblocks\n" + "\nEstimates the approximate fee per kilobyte\n" + "needed for a transaction to get confirmed\n" + "within nblocks blocks.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "n : (numeric) estimated fee-per-kilobyte\n" + "\n" + "-1.0 is returned if not enough transactions and\n" + "blocks have been observed to make an estimate.\n" + "\nExample:\n" + + HelpExampleCli("estimatefee", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(int_type)); + + int nBlocks = params[0].get_int(); + if (nBlocks < 1) + nBlocks = 1; + + CFeeRate feeRate = mempool.estimateFee(nBlocks); + if (feeRate == CFeeRate(0)) + return -1.0; + + return ValueFromAmount(feeRate.GetFeePerK()); +} + +Value estimatepriority(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatepriority nblocks\n" + "\nEstimates the approximate priority\n" + "a zero-fee transaction needs to get confirmed\n" + "within nblocks blocks.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "n : (numeric) estimated priority\n" + "\n" + "-1.0 is returned if not enough transactions and\n" + "blocks have been observed to make an estimate.\n" + "\nExample:\n" + + HelpExampleCli("estimatepriority", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(int_type)); + + int nBlocks = params[0].get_int(); + if (nBlocks < 1) + nBlocks = 1; + + return mempool.estimatePriority(nBlocks); +} diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 27d6d61a3..77e0e09ec 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -73,7 +73,7 @@ Value getinfo(const Array& params, bool fHelp) 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", TestNet())); + obj.push_back(Pair("testnet", Params().RPCisTestNet())); #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); @@ -81,9 +81,9 @@ Value getinfo(const Array& params, bool fHelp) } if (pwalletMain && pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); - obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); #endif - obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::nMinRelayTxFee))); + obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK()))); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 63eed09b6..0eca55a47 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -368,7 +368,7 @@ Value getnetworkinfo(const Array& params, bool fHelp) obj.push_back(Pair("timeoffset", 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("relayfee", ValueFromAmount(CTransaction::nMinRelayTxFee))); + obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK()))); Array localAddresses; { LOCK(cs_mapLocalHost); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2534a9dcf..d4ceb7f99 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -254,7 +254,7 @@ static const CRPCCommand vRPCCommands[] = { "getblocktemplate", &getblocktemplate, true, false, false }, { "getmininginfo", &getmininginfo, true, false, false }, { "getnetworkhashps", &getnetworkhashps, true, false, false }, - { "submitblock", &submitblock, false, false, false }, + { "submitblock", &submitblock, false, true, false }, /* Raw transactions */ { "createrawtransaction", &createrawtransaction, false, false, false }, @@ -268,6 +268,8 @@ static const CRPCCommand vRPCCommands[] = { "createmultisig", &createmultisig, true, true , false }, { "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */ { "verifymessage", &verifymessage, false, false, false }, + { "estimatefee", &estimatefee, true, true, false }, + { "estimatepriority", &estimatepriority, true, true, false }, #ifdef ENABLE_WALLET /* Wallet */ diff --git a/src/rpcserver.h b/src/rpcserver.h index e8cd2cd0f..73e8b9426 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -133,6 +133,8 @@ extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool f 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 estimatefee(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index e3b35dbb0..f376ab6b6 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1883,7 +1883,7 @@ Value settxfee(const Array& params, bool fHelp) if (params[0].get_real() != 0.0) nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts - nTransactionFee = nAmount; + payTxFee = CFeeRate(nAmount, 1000); return true; } diff --git a/src/script.cpp b/src/script.cpp index ac6d4b316..11cdfef95 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -208,14 +208,13 @@ const char* GetOpName(opcodetype opcode) case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + // Note: + // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum + // as kind of implementation hack, they are *NOT* real opcodes. If found in real + // Script, just let the default: case deal with them. - // template matching params - case OP_PUBKEYHASH : return "OP_PUBKEYHASH"; - case OP_PUBKEY : return "OP_PUBKEY"; - case OP_SMALLDATA : return "OP_SMALLDATA"; - - case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: return "OP_UNKNOWN"; } @@ -839,10 +838,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); - ////// debug print - //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n"); - //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n"); - // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); diff --git a/src/script.h b/src/script.h index aed2b7a6a..a282e7dc0 100644 --- a/src/script.h +++ b/src/script.h @@ -691,12 +691,6 @@ public: void SetDestination(const CTxDestination& address); void SetMultisig(int nRequired, const std::vector<CPubKey>& keys); - - void PrintHex() const - { - LogPrintf("CScript(%s)\n", HexStr(begin(), end(), true).c_str()); - } - std::string ToString() const { std::string str; @@ -720,11 +714,6 @@ public: return str; } - void print() const - { - LogPrintf("%s\n", ToString()); - } - CScriptID GetID() const { return CScriptID(Hash160(*this)); diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 000000000..87bf73fec --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,6 @@ +all: + $(MAKE) -C .. bitcoin_test +clean: + $(MAKE) -C .. bitcoin_test_clean +check: + $(MAKE) -C .. bitcoin_test_check diff --git a/src/test/Makefile.am b/src/test/Makefile.am deleted file mode 100644 index cde3a31e2..000000000 --- a/src/test/Makefile.am +++ /dev/null @@ -1,77 +0,0 @@ -include $(top_srcdir)/src/Makefile.include - -AM_CPPFLAGS += -I$(top_srcdir)/src - -bin_PROGRAMS = test_bitcoin - -TESTS = test_bitcoin - -JSON_TEST_FILES = \ - data/script_valid.json \ - data/base58_keys_valid.json \ - data/sig_canonical.json \ - data/sig_noncanonical.json \ - data/base58_encode_decode.json \ - data/base58_keys_invalid.json \ - data/script_invalid.json \ - data/tx_invalid.json \ - data/tx_valid.json \ - data/sighash.json - -RAW_TEST_FILES = data/alertTests.raw - -BUILT_SOURCES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) - -# test_bitcoin binary # -test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS) -test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) -if ENABLE_WALLET -test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) -endif -test_bitcoin_LDADD += $(BDB_LIBS) - -test_bitcoin_SOURCES = \ - bignum.h \ - alert_tests.cpp \ - allocator_tests.cpp \ - base32_tests.cpp \ - base58_tests.cpp \ - base64_tests.cpp \ - bloom_tests.cpp \ - canonical_tests.cpp \ - checkblock_tests.cpp \ - Checkpoints_tests.cpp \ - compress_tests.cpp \ - DoS_tests.cpp \ - getarg_tests.cpp \ - key_tests.cpp \ - main_tests.cpp \ - miner_tests.cpp \ - mruset_tests.cpp \ - multisig_tests.cpp \ - netbase_tests.cpp \ - pmt_tests.cpp \ - rpc_tests.cpp \ - script_P2SH_tests.cpp \ - script_tests.cpp \ - serialize_tests.cpp \ - sigopcount_tests.cpp \ - test_bitcoin.cpp \ - transaction_tests.cpp \ - uint256_tests.cpp \ - util_tests.cpp \ - scriptnum_tests.cpp \ - sighash_tests.cpp \ - $(JSON_TEST_FILES) $(RAW_TEST_FILES) - -if ENABLE_WALLET -test_bitcoin_SOURCES += \ - accounting_tests.cpp \ - wallet_tests.cpp \ - rpc_wallet_tests.cpp -endif - -nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES) - -CLEANFILES = *.gcda *.gcno $(BUILT_SOURCES) diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index eea249b11..1dc2a3d82 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -67,6 +67,31 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) LOCK2(cs_main, pwalletMain->cs_wallet); + CPubKey demoPubkey = pwalletMain->GenerateNewKey(); + CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID())); + Value retValue; + string strAccount = "walletDemoAccount"; + string strPurpose = "receive"; + BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */ + CWalletDB walletdb(pwalletMain->strWalletFile); + CAccount account; + account.vchPubKey = demoPubkey; + pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose); + walletdb.WriteAccount(strAccount, account); + }); + + + /********************************* + * setaccount + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount")); + BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error); + /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */ + BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error); + + /********************************* + * listunspent + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("listunspent")); BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error); BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); @@ -75,6 +100,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []")); BOOST_CHECK(r.get_array().empty()); + /********************************* + * listreceivedbyaddress + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error); @@ -82,12 +110,71 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error); + /********************************* + * listreceivedbyaccount + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error); BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error); BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); + + /********************************* + * getrawchangeaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress")); + + /********************************* + * getnewaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getnewaddress")); + BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount")); + + /********************************* + * getaccountaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\"")); + BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account + BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount)); + BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get()); + + /********************************* + * getaccount + *********************************/ + BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString())); + + /********************************* + * signmessage + verifymessage + *********************************/ + BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage")); + BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error); + /* Should throw error because this address is not loaded in the wallet */ + BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error); + + /* missing arguments */ + BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString()), runtime_error); + BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str()), runtime_error); + /* Illegal address */ + BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error); + /* wrong address */ + BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false); + /* Correct address and signature but wrong message */ + BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false); + /* Correct address, message and signature*/ + BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true); + + /********************************* + * getaddressesbyaccount + *********************************/ + BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error); + BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount)); + Array arr = retValue.get_array(); + BOOST_CHECK(arr.size() > 0); + BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); + } + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 64c9eac73..4bf01d484 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -6,6 +6,8 @@ #include "core.h" #include "txmempool.h" +#include <boost/circular_buffer.hpp> + using namespace std; CTxMemPoolEntry::CTxMemPoolEntry() @@ -35,12 +37,311 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const return dResult; } +// +// Keep track of fee/priority for transactions confirmed within N blocks +// +class CBlockAverage +{ +private: + boost::circular_buffer<CFeeRate> feeSamples; + boost::circular_buffer<double> prioritySamples; + + template<typename T> std::vector<T> buf2vec(boost::circular_buffer<T> buf) const + { + std::vector<T> vec(buf.begin(), buf.end()); + return vec; + } + +public: + CBlockAverage() : feeSamples(100), prioritySamples(100) { } + + void RecordFee(const CFeeRate& feeRate) { + feeSamples.push_back(feeRate); + } + + void RecordPriority(double priority) { + prioritySamples.push_back(priority); + } + + size_t FeeSamples() const { return feeSamples.size(); } + size_t GetFeeSamples(std::vector<CFeeRate>& insertInto) const + { + BOOST_FOREACH(const CFeeRate& f, feeSamples) + insertInto.push_back(f); + return feeSamples.size(); + } + size_t PrioritySamples() const { return prioritySamples.size(); } + size_t GetPrioritySamples(std::vector<double>& insertInto) const + { + BOOST_FOREACH(double d, prioritySamples) + insertInto.push_back(d); + return prioritySamples.size(); + } + + // Used as belt-and-suspenders check when reading to detect + // file corruption + bool AreSane(const std::vector<CFeeRate>& vecFee) + { + BOOST_FOREACH(CFeeRate fee, vecFee) + { + if (fee < CFeeRate(0)) + return false; + if (fee.GetFee(1000) > CTransaction::minRelayTxFee.GetFee(1000) * 10000) + return false; + } + return true; + } + bool AreSane(const std::vector<double> vecPriority) + { + BOOST_FOREACH(double priority, vecPriority) + { + if (priority < 0) + return false; + } + return true; + } + + void Write(CAutoFile& fileout) const + { + std::vector<CFeeRate> vecFee = buf2vec(feeSamples); + fileout << vecFee; + std::vector<double> vecPriority = buf2vec(prioritySamples); + fileout << vecPriority; + } + + void Read(CAutoFile& filein) { + std::vector<CFeeRate> vecFee; + filein >> vecFee; + if (AreSane(vecFee)) + feeSamples.insert(feeSamples.end(), vecFee.begin(), vecFee.end()); + else + throw runtime_error("Corrupt fee value in estimates file."); + std::vector<double> vecPriority; + filein >> vecPriority; + if (AreSane(vecPriority)) + prioritySamples.insert(prioritySamples.end(), vecPriority.begin(), vecPriority.end()); + else + throw runtime_error("Corrupt priority value in estimates file."); + if (feeSamples.size() + prioritySamples.size() > 0) + LogPrint("estimatefee", "Read %d fee samples and %d priority samples\n", + feeSamples.size(), prioritySamples.size()); + } +}; + +class CMinerPolicyEstimator +{ +private: + // Records observed averages transactions that confirmed within one block, two blocks, + // three blocks etc. + std::vector<CBlockAverage> history; + std::vector<CFeeRate> sortedFeeSamples; + std::vector<double> sortedPrioritySamples; + + int nBestSeenHeight; + + // nBlocksAgo is 0 based, i.e. transactions that confirmed in the highest seen block are + // nBlocksAgo == 0, transactions in the block before that are nBlocksAgo == 1 etc. + void seenTxConfirm(CFeeRate feeRate, double dPriority, int nBlocksAgo) + { + // Last entry records "everything else". + int nBlocksTruncated = min(nBlocksAgo, (int) history.size() - 1); + assert(nBlocksTruncated >= 0); + + // We need to guess why the transaction was included in a block-- either + // because it is high-priority or because it has sufficient fees. + bool sufficientFee = (feeRate > CTransaction::minRelayTxFee); + bool sufficientPriority = AllowFree(dPriority); + const char* assignedTo = "unassigned"; + if (sufficientFee && !sufficientPriority) + { + history[nBlocksTruncated].RecordFee(feeRate); + assignedTo = "fee"; + } + else if (sufficientPriority && !sufficientFee) + { + history[nBlocksTruncated].RecordPriority(dPriority); + assignedTo = "priority"; + } + else + { + // Neither or both fee and priority sufficient to get confirmed: + // don't know why they got confirmed. + } + LogPrint("estimatefee", "Seen TX confirm: %s : %s fee/%g priority, took %d blocks\n", + assignedTo, feeRate.ToString(), dPriority, nBlocksAgo); + } + +public: + CMinerPolicyEstimator(int nEntries) : nBestSeenHeight(0) + { + history.resize(nEntries); + } + + void seenBlock(const std::vector<CTxMemPoolEntry>& entries, int nBlockHeight) + { + if (nBlockHeight <= nBestSeenHeight) + { + // Ignore side chains and re-orgs; assuming they are random + // they don't affect the estimate. + // And if an attacker can re-org the chain at will, then + // you've got much bigger problems than "attacker can influence + // transaction fees." + return; + } + nBestSeenHeight = nBlockHeight; + + // Fill up the history buckets based on how long transactions took + // to confirm. + std::vector<std::vector<const CTxMemPoolEntry*> > entriesByConfirmations; + entriesByConfirmations.resize(history.size()); + BOOST_FOREACH(const CTxMemPoolEntry& entry, entries) + { + // How many blocks did it take for miners to include this transaction? + int delta = nBlockHeight - entry.GetHeight(); + if (delta <= 0) + { + // Re-org made us lose height, this should only happen if we happen + // to re-org on a difficulty transition point: very rare! + continue; + } + if ((delta-1) >= (int)history.size()) + delta = history.size(); // Last bucket is catch-all + entriesByConfirmations[delta-1].push_back(&entry); + } + for (size_t i = 0; i < entriesByConfirmations.size(); i++) + { + std::vector<const CTxMemPoolEntry*> &e = entriesByConfirmations.at(i); + // Insert at most 10 random entries per bucket, otherwise a single block + // can dominate an estimate: + if (e.size() > 10) { + std::random_shuffle(e.begin(), e.end()); + e.resize(10); + } + BOOST_FOREACH(const CTxMemPoolEntry* entry, e) + { + // Fees are stored and reported as BTC-per-kb: + CFeeRate feeRate(entry->GetFee(), entry->GetTxSize()); + double dPriority = entry->GetPriority(entry->GetHeight()); // Want priority when it went IN + seenTxConfirm(feeRate, dPriority, i); + } + } + for (size_t i = 0; i < history.size(); i++) { + if (history[i].FeeSamples() + history[i].PrioritySamples() > 0) + LogPrint("estimatefee", "estimates: for confirming within %d blocks based on %d/%d samples, fee=%s, prio=%g\n", + i, + history[i].FeeSamples(), history[i].PrioritySamples(), + estimateFee(i+1).ToString(), estimatePriority(i+1)); + } + sortedFeeSamples.clear(); + sortedPrioritySamples.clear(); + } + + // Can return CFeeRate(0) if we don't have any data for that many blocks back. nBlocksToConfirm is 1 based. + CFeeRate estimateFee(int nBlocksToConfirm) + { + nBlocksToConfirm--; + + if (nBlocksToConfirm < 0 || nBlocksToConfirm >= (int)history.size()) + return CFeeRate(0); + + if (sortedFeeSamples.size() == 0) + { + for (size_t i = 0; i < history.size(); i++) + history.at(i).GetFeeSamples(sortedFeeSamples); + std::sort(sortedFeeSamples.begin(), sortedFeeSamples.end(), + std::greater<CFeeRate>()); + } + if (sortedFeeSamples.size() == 0) + return CFeeRate(0); + + int nBucketSize = history.at(nBlocksToConfirm).FeeSamples(); + + // Estimates should not increase as number of confirmations goes up, + // but the estimates are noisy because confirmations happen discretely + // in blocks. To smooth out the estimates, use all samples in the history + // and use the nth highest where n is (number of samples in previous bucket + + // half the samples in nBlocksToConfirm bucket): + size_t nPrevSize = 0; + for (int i = 0; i < nBlocksToConfirm; i++) + nPrevSize += history.at(i).FeeSamples(); + size_t index = min(nPrevSize + nBucketSize/2, sortedFeeSamples.size()-1); + return sortedFeeSamples[index]; + } + double estimatePriority(int nBlocksToConfirm) + { + nBlocksToConfirm--; + + if (nBlocksToConfirm < 0 || nBlocksToConfirm >= (int)history.size()) + return -1; + + if (sortedPrioritySamples.size() == 0) + { + for (size_t i = 0; i < history.size(); i++) + history.at(i).GetPrioritySamples(sortedPrioritySamples); + std::sort(sortedPrioritySamples.begin(), sortedPrioritySamples.end(), + std::greater<double>()); + } + if (sortedPrioritySamples.size() == 0) + return -1.0; + + int nBucketSize = history.at(nBlocksToConfirm).PrioritySamples(); + + // Estimates should not increase as number of confirmations needed goes up, + // but the estimates are noisy because confirmations happen discretely + // in blocks. To smooth out the estimates, use all samples in the history + // and use the nth highest where n is (number of samples in previous buckets + + // half the samples in nBlocksToConfirm bucket). + size_t nPrevSize = 0; + for (int i = 0; i < nBlocksToConfirm; i++) + nPrevSize += history.at(i).PrioritySamples(); + size_t index = min(nPrevSize + nBucketSize/2, sortedFeeSamples.size()-1); + return sortedPrioritySamples[index]; + } + + void Write(CAutoFile& fileout) const + { + fileout << nBestSeenHeight; + fileout << history.size(); + BOOST_FOREACH(const CBlockAverage& entry, history) + { + entry.Write(fileout); + } + } + + void Read(CAutoFile& filein) + { + filein >> nBestSeenHeight; + size_t numEntries; + filein >> numEntries; + history.clear(); + for (size_t i = 0; i < numEntries; i++) + { + CBlockAverage entry; + entry.Read(filein); + history.push_back(entry); + } + } +}; + + CTxMemPool::CTxMemPool() { // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number // of transactions in the pool fSanityCheck = false; + + // 25 blocks is a compromise between using a lot of disk/memory and + // trying to give accurate estimates to people who might be willing + // to wait a day or two to save a fraction of a penny in fees. + // Confirmation times for very-low-fee transactions that take more + // than an hour or three to confirm are highly variable. + minerPolicyEstimator = new CMinerPolicyEstimator(25); +} + +CTxMemPool::~CTxMemPool() +{ + delete minerPolicyEstimator; } void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) @@ -128,6 +429,28 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction> } } +// Called when a block is connected. Removes from mempool and updates the miner fee estimator. +void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, + std::list<CTransaction>& conflicts) +{ + LOCK(cs); + std::vector<CTxMemPoolEntry> entries; + BOOST_FOREACH(const CTransaction& tx, vtx) + { + uint256 hash = tx.GetHash(); + if (mapTx.count(hash)) + entries.push_back(mapTx[hash]); + } + minerPolicyEstimator->seenBlock(entries, nBlockHeight); + BOOST_FOREACH(const CTransaction& tx, vtx) + { + std::list<CTransaction> dummy; + remove(tx, dummy, false); + removeConflicts(tx, conflicts); + } +} + + void CTxMemPool::clear() { LOCK(cs); @@ -195,6 +518,53 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const return true; } +CFeeRate CTxMemPool::estimateFee(int nBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateFee(nBlocks); +} +double CTxMemPool::estimatePriority(int nBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimatePriority(nBlocks); +} + +bool +CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const +{ + try { + LOCK(cs); + fileout << 99900; // version required to read: 0.9.99 or later + fileout << CLIENT_VERSION; // version that wrote the file + minerPolicyEstimator->Write(fileout); + } + catch (std::exception &e) { + LogPrintf("CTxMemPool::WriteFeeEstimates() : unable to write policy estimator data (non-fatal)"); + return false; + } + return true; +} + +bool +CTxMemPool::ReadFeeEstimates(CAutoFile& filein) +{ + try { + int nVersionRequired, nVersionThatWrote; + filein >> nVersionRequired >> nVersionThatWrote; + if (nVersionRequired > CLIENT_VERSION) + return error("CTxMemPool::ReadFeeEstimates() : up-version (%d) fee estimate file", nVersionRequired); + + LOCK(cs); + minerPolicyEstimator->Read(filein); + } + catch (std::exception &e) { + LogPrintf("CTxMemPool::ReadFeeEstimates() : unable to read policy estimator data (non-fatal)"); + return false; + } + return true; +} + + CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { diff --git a/src/txmempool.h b/src/txmempool.h index 4509e9577..b2915aa84 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -11,6 +11,13 @@ #include "core.h" #include "sync.h" +inline bool AllowFree(double dPriority) +{ + // Large (in bytes) low-priority (new, small-coin) transactions + // need a fee. + return dPriority > COIN * 144 / 250; +} + /** 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; @@ -41,6 +48,8 @@ public: unsigned int GetHeight() const { return nHeight; } }; +class CMinerPolicyEstimator; + /* * CTxMemPool stores valid-according-to-the-current-best-chain * transactions that may be included in the next block. @@ -56,6 +65,7 @@ class CTxMemPool private: bool fSanityCheck; // Normally false, true if -checkmempool or -regtest unsigned int nTransactionsUpdated; + CMinerPolicyEstimator* minerPolicyEstimator; public: mutable CCriticalSection cs; @@ -63,6 +73,7 @@ public: std::map<COutPoint, CInPoint> mapNextTx; CTxMemPool(); + ~CTxMemPool(); /* * If sanity-checking is turned on, check makes sure the pool is @@ -76,6 +87,8 @@ public: bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry); void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false); void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed); + void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, + std::list<CTransaction>& conflicts); void clear(); void queryHashes(std::vector<uint256>& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); @@ -95,6 +108,16 @@ public: } bool lookup(uint256 hash, CTransaction& result) const; + + // Estimate fee rate needed to get into the next + // nBlocks + CFeeRate estimateFee(int nBlocks) const; + // Estimate priority needed to get into the next + // nBlocks + double estimatePriority(int nBlocks) const; + // Write/Read estimates to disk + bool WriteFeeEstimates(CAutoFile& fileout) const; + bool ReadFeeEstimates(CAutoFile& filein); }; /** CCoinsView that brings transactions from a memorypool into view. diff --git a/src/ui_interface.h b/src/ui_interface.h index 7b655ac95..e1a3e04e1 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -94,6 +94,9 @@ public: /** A wallet has been loaded. */ boost::signals2::signal<void (CWallet* wallet)> LoadWallet; + + /** Show progress e.g. for verifychain */ + boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; }; extern CClientUIInterface uiInterface; diff --git a/src/util.cpp b/src/util.cpp index 336ef3172..d106b0323 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -94,7 +94,6 @@ bool fPrintToDebugLog = true; bool fDaemon = false; bool fServer = false; string strMiscWarning; -bool fNoListen = false; bool fLogTimestamps = false; volatile bool fReopenDebugLog = false; CClientUIInterface uiInterface; diff --git a/src/util.h b/src/util.h index ffcb20d82..e07036579 100644 --- a/src/util.h +++ b/src/util.h @@ -100,7 +100,6 @@ extern bool fPrintToConsole; extern bool fPrintToDebugLog; extern bool fServer; extern std::string strMiscWarning; -extern bool fNoListen; extern bool fLogTimestamps; extern volatile bool fReopenDebugLog; @@ -287,17 +286,6 @@ inline std::string HexStr(const T& vch, bool fSpaces=false) return HexStr(vch.begin(), vch.end(), fSpaces); } -template<typename T> -void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true) -{ - LogPrintf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str()); -} - -inline void PrintHex(const std::vector<unsigned char>& vch, const char* pszFormat="%s", bool fSpaces=true) -{ - LogPrintf(pszFormat, HexStr(vch, fSpaces).c_str()); -} - inline int64_t GetPerformanceCounter() { int64_t nCounter = 0; diff --git a/src/wallet.cpp b/src/wallet.cpp index 89604f96a..ef0b442e1 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -16,7 +16,7 @@ using namespace std; // Settings -int64_t nTransactionFee = DEFAULT_TRANSACTION_FEE; +CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); bool bSpendZeroConfChange = true; ////////////////////////////////////////////////////////////////////////////// @@ -1233,7 +1233,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, { LOCK2(cs_main, cs_wallet); { - nFeeRet = nTransactionFee; + nFeeRet = payTxFee.GetFeePerK(); while (true) { wtxNew.vin.clear(); @@ -1246,7 +1246,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend) { CTxOut txout(s.second, s.first); - if (txout.IsDust(CTransaction::nMinRelayTxFee)) + if (txout.IsDust(CTransaction::minRelayTxFee)) { strFailReason = _("Transaction amount too small"); return false; @@ -1272,16 +1272,6 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, } int64_t nChange = nValueIn - nValue - nFeeRet; - // The following if statement should be removed once enough miners - // have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids - // creating free transactions that have change outputs less than - // CENT bitcoins. - if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) - { - int64_t nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); - nChange -= nMoveToFee; - nFeeRet += nMoveToFee; - } if (nChange > 0) { @@ -1317,7 +1307,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, // Never create dust outputs; if we would, just // add the dust to the fee. - if (newTxOut.IsDust(CTransaction::nMinRelayTxFee)) + if (newTxOut.IsDust(CTransaction::minRelayTxFee)) { nFeeRet += nChange; reservekey.ReturnKey(); @@ -1355,7 +1345,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, dPriority = wtxNew.ComputePriority(dPriority, nBytes); // Check that enough fee is included - int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); + int64_t nPayFee = payTxFee.GetFee(nBytes); bool fAllowFree = AllowFree(dPriority); int64_t nMinFee = GetMinFee(wtxNew, nBytes, fAllowFree, GMF_SEND); if (nFeeRet < max(nPayFee, nMinFee)) @@ -1464,7 +1454,7 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nV // Check amount if (nValue <= 0) return _("Invalid amount"); - if (nValue + nTransactionFee > GetBalance()) + if (nValue > GetBalance()) return _("Insufficient funds"); // Parse Bitcoin address diff --git a/src/wallet.h b/src/wallet.h index 96074151a..274c31157 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -24,7 +24,7 @@ #include <vector> // Settings -extern int64_t nTransactionFee; +extern CFeeRate payTxFee; extern bool bSpendZeroConfChange; // -paytxfee default @@ -143,26 +143,26 @@ public: CWallet() { - nWalletVersion = FEATURE_BASE; - nWalletMaxVersion = FEATURE_BASE; - fFileBacked = false; - nMasterKeyMaxID = 0; - pwalletdbEncryption = NULL; - nOrderPosNext = 0; - nNextResend = 0; - nLastResend = 0; + SetNull(); } CWallet(std::string strWalletFileIn) { - nWalletVersion = FEATURE_BASE; - nWalletMaxVersion = FEATURE_BASE; + SetNull(); + strWalletFile = strWalletFileIn; fFileBacked = true; + } + void SetNull() + { + nWalletVersion = FEATURE_BASE; + nWalletMaxVersion = FEATURE_BASE; + fFileBacked = false; nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; nOrderPosNext = 0; nNextResend = 0; nLastResend = 0; + nTimeFirstKey = 0; } std::map<uint256, CWalletTx> mapWallet; |